theme.js 1.1 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238302393024030241302423024330244302453024630247302483024930250302513025230253302543025530256302573025830259302603026130262302633026430265302663026730268302693027030271302723027330274302753027630277302783027930280302813028230283302843028530286302873028830289302903029130292302933029430295302963029730298302993030030301303023030330304303053030630307303083030930310303113031230313303143031530316303173031830319303203032130322303233032430325303263032730328303293033030331303323033330334303353033630337303383033930340303413034230343303443034530346303473034830349303503035130352303533035430355303563035730358303593036030361303623036330364303653036630367303683036930370303713037230373303743037530376303773037830379303803038130382303833038430385303863038730388303893039030391303923039330394303953039630397303983039930400304013040230403304043040530406304073040830409304103041130412304133041430415304163041730418304193042030421304223042330424304253042630427304283042930430304313043230433304343043530436304373043830439304403044130442304433044430445304463044730448304493045030451304523045330454304553045630457304583045930460304613046230463304643046530466304673046830469304703047130472304733047430475304763047730478304793048030481304823048330484304853048630487304883048930490304913049230493304943049530496304973049830499305003050130502305033050430505305063050730508305093051030511305123051330514305153051630517305183051930520305213052230523305243052530526305273052830529305303053130532305333053430535305363053730538305393054030541305423054330544305453054630547305483054930550305513055230553305543055530556305573055830559305603056130562305633056430565305663056730568305693057030571305723057330574305753057630577305783057930580305813058230583305843058530586305873058830589305903059130592305933059430595305963059730598305993060030601306023060330604306053060630607306083060930610306113061230613306143061530616306173061830619306203062130622306233062430625306263062730628306293063030631306323063330634306353063630637306383063930640306413064230643306443064530646306473064830649306503065130652306533065430655306563065730658306593066030661306623066330664306653066630667306683066930670306713067230673306743067530676306773067830679306803068130682306833068430685306863068730688306893069030691306923069330694306953069630697306983069930700307013070230703307043070530706307073070830709307103071130712307133071430715307163071730718307193072030721307223072330724307253072630727307283072930730307313073230733307343073530736307373073830739307403074130742307433074430745307463074730748307493075030751307523075330754307553075630757307583075930760307613076230763307643076530766307673076830769307703077130772307733077430775
  1. /**
  2. * TinyMCE version 6.8.6 (TBD)
  3. */
  4. (function () {
  5. 'use strict';
  6. const getPrototypeOf$2 = Object.getPrototypeOf;
  7. const hasProto = (v, constructor, predicate) => {
  8. var _a;
  9. if (predicate(v, constructor.prototype)) {
  10. return true;
  11. } else {
  12. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  13. }
  14. };
  15. const typeOf = x => {
  16. const t = typeof x;
  17. if (x === null) {
  18. return 'null';
  19. } else if (t === 'object' && Array.isArray(x)) {
  20. return 'array';
  21. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  22. return 'string';
  23. } else {
  24. return t;
  25. }
  26. };
  27. const isType$1 = type => value => typeOf(value) === type;
  28. const isSimpleType = type => value => typeof value === type;
  29. const eq$1 = t => a => t === a;
  30. const is$2 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$2(o) === proto);
  31. const isString = isType$1('string');
  32. const isObject = isType$1('object');
  33. const isPlainObject = value => is$2(value, Object);
  34. const isArray = isType$1('array');
  35. const isNull = eq$1(null);
  36. const isBoolean = isSimpleType('boolean');
  37. const isUndefined = eq$1(undefined);
  38. const isNullable = a => a === null || a === undefined;
  39. const isNonNullable = a => !isNullable(a);
  40. const isFunction = isSimpleType('function');
  41. const isNumber = isSimpleType('number');
  42. const isArrayOf = (value, pred) => {
  43. if (isArray(value)) {
  44. for (let i = 0, len = value.length; i < len; ++i) {
  45. if (!pred(value[i])) {
  46. return false;
  47. }
  48. }
  49. return true;
  50. }
  51. return false;
  52. };
  53. const noop = () => {
  54. };
  55. const noarg = f => () => f();
  56. const compose = (fa, fb) => {
  57. return (...args) => {
  58. return fa(fb.apply(null, args));
  59. };
  60. };
  61. const compose1 = (fbc, fab) => a => fbc(fab(a));
  62. const constant$1 = value => {
  63. return () => {
  64. return value;
  65. };
  66. };
  67. const identity = x => {
  68. return x;
  69. };
  70. const tripleEquals = (a, b) => {
  71. return a === b;
  72. };
  73. function curry(fn, ...initialArgs) {
  74. return (...restArgs) => {
  75. const all = initialArgs.concat(restArgs);
  76. return fn.apply(null, all);
  77. };
  78. }
  79. const not = f => t => !f(t);
  80. const die = msg => {
  81. return () => {
  82. throw new Error(msg);
  83. };
  84. };
  85. const apply$1 = f => {
  86. return f();
  87. };
  88. const never = constant$1(false);
  89. const always = constant$1(true);
  90. class Optional {
  91. constructor(tag, value) {
  92. this.tag = tag;
  93. this.value = value;
  94. }
  95. static some(value) {
  96. return new Optional(true, value);
  97. }
  98. static none() {
  99. return Optional.singletonNone;
  100. }
  101. fold(onNone, onSome) {
  102. if (this.tag) {
  103. return onSome(this.value);
  104. } else {
  105. return onNone();
  106. }
  107. }
  108. isSome() {
  109. return this.tag;
  110. }
  111. isNone() {
  112. return !this.tag;
  113. }
  114. map(mapper) {
  115. if (this.tag) {
  116. return Optional.some(mapper(this.value));
  117. } else {
  118. return Optional.none();
  119. }
  120. }
  121. bind(binder) {
  122. if (this.tag) {
  123. return binder(this.value);
  124. } else {
  125. return Optional.none();
  126. }
  127. }
  128. exists(predicate) {
  129. return this.tag && predicate(this.value);
  130. }
  131. forall(predicate) {
  132. return !this.tag || predicate(this.value);
  133. }
  134. filter(predicate) {
  135. if (!this.tag || predicate(this.value)) {
  136. return this;
  137. } else {
  138. return Optional.none();
  139. }
  140. }
  141. getOr(replacement) {
  142. return this.tag ? this.value : replacement;
  143. }
  144. or(replacement) {
  145. return this.tag ? this : replacement;
  146. }
  147. getOrThunk(thunk) {
  148. return this.tag ? this.value : thunk();
  149. }
  150. orThunk(thunk) {
  151. return this.tag ? this : thunk();
  152. }
  153. getOrDie(message) {
  154. if (!this.tag) {
  155. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  156. } else {
  157. return this.value;
  158. }
  159. }
  160. static from(value) {
  161. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  162. }
  163. getOrNull() {
  164. return this.tag ? this.value : null;
  165. }
  166. getOrUndefined() {
  167. return this.value;
  168. }
  169. each(worker) {
  170. if (this.tag) {
  171. worker(this.value);
  172. }
  173. }
  174. toArray() {
  175. return this.tag ? [this.value] : [];
  176. }
  177. toString() {
  178. return this.tag ? `some(${ this.value })` : 'none()';
  179. }
  180. }
  181. Optional.singletonNone = new Optional(false);
  182. const nativeSlice = Array.prototype.slice;
  183. const nativeIndexOf = Array.prototype.indexOf;
  184. const nativePush = Array.prototype.push;
  185. const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  186. const indexOf = (xs, x) => {
  187. const r = rawIndexOf(xs, x);
  188. return r === -1 ? Optional.none() : Optional.some(r);
  189. };
  190. const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
  191. const exists = (xs, pred) => {
  192. for (let i = 0, len = xs.length; i < len; i++) {
  193. const x = xs[i];
  194. if (pred(x, i)) {
  195. return true;
  196. }
  197. }
  198. return false;
  199. };
  200. const range$2 = (num, f) => {
  201. const r = [];
  202. for (let i = 0; i < num; i++) {
  203. r.push(f(i));
  204. }
  205. return r;
  206. };
  207. const chunk$1 = (array, size) => {
  208. const r = [];
  209. for (let i = 0; i < array.length; i += size) {
  210. const s = nativeSlice.call(array, i, i + size);
  211. r.push(s);
  212. }
  213. return r;
  214. };
  215. const map$2 = (xs, f) => {
  216. const len = xs.length;
  217. const r = new Array(len);
  218. for (let i = 0; i < len; i++) {
  219. const x = xs[i];
  220. r[i] = f(x, i);
  221. }
  222. return r;
  223. };
  224. const each$1 = (xs, f) => {
  225. for (let i = 0, len = xs.length; i < len; i++) {
  226. const x = xs[i];
  227. f(x, i);
  228. }
  229. };
  230. const eachr = (xs, f) => {
  231. for (let i = xs.length - 1; i >= 0; i--) {
  232. const x = xs[i];
  233. f(x, i);
  234. }
  235. };
  236. const partition$3 = (xs, pred) => {
  237. const pass = [];
  238. const fail = [];
  239. for (let i = 0, len = xs.length; i < len; i++) {
  240. const x = xs[i];
  241. const arr = pred(x, i) ? pass : fail;
  242. arr.push(x);
  243. }
  244. return {
  245. pass,
  246. fail
  247. };
  248. };
  249. const filter$2 = (xs, pred) => {
  250. const r = [];
  251. for (let i = 0, len = xs.length; i < len; i++) {
  252. const x = xs[i];
  253. if (pred(x, i)) {
  254. r.push(x);
  255. }
  256. }
  257. return r;
  258. };
  259. const foldr = (xs, f, acc) => {
  260. eachr(xs, (x, i) => {
  261. acc = f(acc, x, i);
  262. });
  263. return acc;
  264. };
  265. const foldl = (xs, f, acc) => {
  266. each$1(xs, (x, i) => {
  267. acc = f(acc, x, i);
  268. });
  269. return acc;
  270. };
  271. const findUntil = (xs, pred, until) => {
  272. for (let i = 0, len = xs.length; i < len; i++) {
  273. const x = xs[i];
  274. if (pred(x, i)) {
  275. return Optional.some(x);
  276. } else if (until(x, i)) {
  277. break;
  278. }
  279. }
  280. return Optional.none();
  281. };
  282. const find$5 = (xs, pred) => {
  283. return findUntil(xs, pred, never);
  284. };
  285. const findIndex$1 = (xs, pred) => {
  286. for (let i = 0, len = xs.length; i < len; i++) {
  287. const x = xs[i];
  288. if (pred(x, i)) {
  289. return Optional.some(i);
  290. }
  291. }
  292. return Optional.none();
  293. };
  294. const flatten = xs => {
  295. const r = [];
  296. for (let i = 0, len = xs.length; i < len; ++i) {
  297. if (!isArray(xs[i])) {
  298. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  299. }
  300. nativePush.apply(r, xs[i]);
  301. }
  302. return r;
  303. };
  304. const bind$3 = (xs, f) => flatten(map$2(xs, f));
  305. const forall = (xs, pred) => {
  306. for (let i = 0, len = xs.length; i < len; ++i) {
  307. const x = xs[i];
  308. if (pred(x, i) !== true) {
  309. return false;
  310. }
  311. }
  312. return true;
  313. };
  314. const reverse = xs => {
  315. const r = nativeSlice.call(xs, 0);
  316. r.reverse();
  317. return r;
  318. };
  319. const difference = (a1, a2) => filter$2(a1, x => !contains$2(a2, x));
  320. const mapToObject = (xs, f) => {
  321. const r = {};
  322. for (let i = 0, len = xs.length; i < len; i++) {
  323. const x = xs[i];
  324. r[String(x)] = f(x, i);
  325. }
  326. return r;
  327. };
  328. const pure$2 = x => [x];
  329. const sort = (xs, comparator) => {
  330. const copy = nativeSlice.call(xs, 0);
  331. copy.sort(comparator);
  332. return copy;
  333. };
  334. const get$h = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  335. const head = xs => get$h(xs, 0);
  336. const last$1 = xs => get$h(xs, xs.length - 1);
  337. const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
  338. const findMap = (arr, f) => {
  339. for (let i = 0; i < arr.length; i++) {
  340. const r = f(arr[i], i);
  341. if (r.isSome()) {
  342. return r;
  343. }
  344. }
  345. return Optional.none();
  346. };
  347. const keys = Object.keys;
  348. const hasOwnProperty = Object.hasOwnProperty;
  349. const each = (obj, f) => {
  350. const props = keys(obj);
  351. for (let k = 0, len = props.length; k < len; k++) {
  352. const i = props[k];
  353. const x = obj[i];
  354. f(x, i);
  355. }
  356. };
  357. const map$1 = (obj, f) => {
  358. return tupleMap(obj, (x, i) => ({
  359. k: i,
  360. v: f(x, i)
  361. }));
  362. };
  363. const tupleMap = (obj, f) => {
  364. const r = {};
  365. each(obj, (x, i) => {
  366. const tuple = f(x, i);
  367. r[tuple.k] = tuple.v;
  368. });
  369. return r;
  370. };
  371. const objAcc = r => (x, i) => {
  372. r[i] = x;
  373. };
  374. const internalFilter = (obj, pred, onTrue, onFalse) => {
  375. each(obj, (x, i) => {
  376. (pred(x, i) ? onTrue : onFalse)(x, i);
  377. });
  378. };
  379. const bifilter = (obj, pred) => {
  380. const t = {};
  381. const f = {};
  382. internalFilter(obj, pred, objAcc(t), objAcc(f));
  383. return {
  384. t,
  385. f
  386. };
  387. };
  388. const filter$1 = (obj, pred) => {
  389. const t = {};
  390. internalFilter(obj, pred, objAcc(t), noop);
  391. return t;
  392. };
  393. const mapToArray = (obj, f) => {
  394. const r = [];
  395. each(obj, (value, name) => {
  396. r.push(f(value, name));
  397. });
  398. return r;
  399. };
  400. const find$4 = (obj, pred) => {
  401. const props = keys(obj);
  402. for (let k = 0, len = props.length; k < len; k++) {
  403. const i = props[k];
  404. const x = obj[i];
  405. if (pred(x, i, obj)) {
  406. return Optional.some(x);
  407. }
  408. }
  409. return Optional.none();
  410. };
  411. const values = obj => {
  412. return mapToArray(obj, identity);
  413. };
  414. const get$g = (obj, key) => {
  415. return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
  416. };
  417. const has$2 = (obj, key) => hasOwnProperty.call(obj, key);
  418. const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
  419. const is$1 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  420. const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
  421. const cat = arr => {
  422. const r = [];
  423. const push = x => {
  424. r.push(x);
  425. };
  426. for (let i = 0; i < arr.length; i++) {
  427. arr[i].each(push);
  428. }
  429. return r;
  430. };
  431. const sequence = arr => {
  432. const r = [];
  433. for (let i = 0; i < arr.length; i++) {
  434. const x = arr[i];
  435. if (x.isSome()) {
  436. r.push(x.getOrDie());
  437. } else {
  438. return Optional.none();
  439. }
  440. }
  441. return Optional.some(r);
  442. };
  443. const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  444. const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
  445. const mapFrom = (a, f) => a !== undefined && a !== null ? Optional.some(f(a)) : Optional.none();
  446. const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  447. const addToEnd = (str, suffix) => {
  448. return str + suffix;
  449. };
  450. const removeFromStart = (str, numChars) => {
  451. return str.substring(numChars);
  452. };
  453. const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  454. const removeLeading = (str, prefix) => {
  455. return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  456. };
  457. const ensureTrailing = (str, suffix) => {
  458. return endsWith(str, suffix) ? str : addToEnd(str, suffix);
  459. };
  460. const contains$1 = (str, substr, start = 0, end) => {
  461. const idx = str.indexOf(substr, start);
  462. if (idx !== -1) {
  463. return isUndefined(end) ? true : idx + substr.length <= end;
  464. } else {
  465. return false;
  466. }
  467. };
  468. const startsWith = (str, prefix) => {
  469. return checkRange(str, prefix, 0);
  470. };
  471. const endsWith = (str, suffix) => {
  472. return checkRange(str, suffix, str.length - suffix.length);
  473. };
  474. const blank = r => s => s.replace(r, '');
  475. const trim$1 = blank(/^\s+|\s+$/g);
  476. const isNotEmpty = s => s.length > 0;
  477. const isEmpty = s => !isNotEmpty(s);
  478. const isSupported$1 = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  479. const fromHtml$2 = (html, scope) => {
  480. const doc = scope || document;
  481. const div = doc.createElement('div');
  482. div.innerHTML = html;
  483. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  484. const message = 'HTML does not have a single root node';
  485. console.error(message, html);
  486. throw new Error(message);
  487. }
  488. return fromDom(div.childNodes[0]);
  489. };
  490. const fromTag = (tag, scope) => {
  491. const doc = scope || document;
  492. const node = doc.createElement(tag);
  493. return fromDom(node);
  494. };
  495. const fromText = (text, scope) => {
  496. const doc = scope || document;
  497. const node = doc.createTextNode(text);
  498. return fromDom(node);
  499. };
  500. const fromDom = node => {
  501. if (node === null || node === undefined) {
  502. throw new Error('Node cannot be null or undefined');
  503. }
  504. return { dom: node };
  505. };
  506. const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  507. const SugarElement = {
  508. fromHtml: fromHtml$2,
  509. fromTag,
  510. fromText,
  511. fromDom,
  512. fromPoint
  513. };
  514. const Global = typeof window !== 'undefined' ? window : Function('return this;')();
  515. const path$1 = (parts, scope) => {
  516. let o = scope !== undefined && scope !== null ? scope : Global;
  517. for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
  518. o = o[parts[i]];
  519. }
  520. return o;
  521. };
  522. const resolve = (p, scope) => {
  523. const parts = p.split('.');
  524. return path$1(parts, scope);
  525. };
  526. const unsafe = (name, scope) => {
  527. return resolve(name, scope);
  528. };
  529. const getOrDie$1 = (name, scope) => {
  530. const actual = unsafe(name, scope);
  531. if (actual === undefined || actual === null) {
  532. throw new Error(name + ' not available on this browser');
  533. }
  534. return actual;
  535. };
  536. const getPrototypeOf$1 = Object.getPrototypeOf;
  537. const sandHTMLElement = scope => {
  538. return getOrDie$1('HTMLElement', scope);
  539. };
  540. const isPrototypeOf = x => {
  541. const scope = resolve('ownerDocument.defaultView', x);
  542. return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf$1(x).constructor.name));
  543. };
  544. const DOCUMENT = 9;
  545. const DOCUMENT_FRAGMENT = 11;
  546. const ELEMENT = 1;
  547. const TEXT = 3;
  548. const name$3 = element => {
  549. const r = element.dom.nodeName;
  550. return r.toLowerCase();
  551. };
  552. const type$1 = element => element.dom.nodeType;
  553. const isType = t => element => type$1(element) === t;
  554. const isHTMLElement = element => isElement$1(element) && isPrototypeOf(element.dom);
  555. const isElement$1 = isType(ELEMENT);
  556. const isText = isType(TEXT);
  557. const isDocument = isType(DOCUMENT);
  558. const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  559. const isTag = tag => e => isElement$1(e) && name$3(e) === tag;
  560. const is = (element, selector) => {
  561. const dom = element.dom;
  562. if (dom.nodeType !== ELEMENT) {
  563. return false;
  564. } else {
  565. const elem = dom;
  566. if (elem.matches !== undefined) {
  567. return elem.matches(selector);
  568. } else if (elem.msMatchesSelector !== undefined) {
  569. return elem.msMatchesSelector(selector);
  570. } else if (elem.webkitMatchesSelector !== undefined) {
  571. return elem.webkitMatchesSelector(selector);
  572. } else if (elem.mozMatchesSelector !== undefined) {
  573. return elem.mozMatchesSelector(selector);
  574. } else {
  575. throw new Error('Browser lacks native selectors');
  576. }
  577. }
  578. };
  579. const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  580. const all$3 = (selector, scope) => {
  581. const base = scope === undefined ? document : scope.dom;
  582. return bypassSelector(base) ? [] : map$2(base.querySelectorAll(selector), SugarElement.fromDom);
  583. };
  584. const one = (selector, scope) => {
  585. const base = scope === undefined ? document : scope.dom;
  586. return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
  587. };
  588. const eq = (e1, e2) => e1.dom === e2.dom;
  589. const contains = (e1, e2) => {
  590. const d1 = e1.dom;
  591. const d2 = e2.dom;
  592. return d1 === d2 ? false : d1.contains(d2);
  593. };
  594. const owner$4 = element => SugarElement.fromDom(element.dom.ownerDocument);
  595. const documentOrOwner = dos => isDocument(dos) ? dos : owner$4(dos);
  596. const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
  597. const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
  598. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  599. const parentNode = element => parent(element);
  600. const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
  601. const parents = (element, isRoot) => {
  602. const stop = isFunction(isRoot) ? isRoot : never;
  603. let dom = element.dom;
  604. const ret = [];
  605. while (dom.parentNode !== null && dom.parentNode !== undefined) {
  606. const rawParent = dom.parentNode;
  607. const p = SugarElement.fromDom(rawParent);
  608. ret.push(p);
  609. if (stop(p) === true) {
  610. break;
  611. } else {
  612. dom = rawParent;
  613. }
  614. }
  615. return ret;
  616. };
  617. const offsetParent = element => Optional.from(element.dom.offsetParent).map(SugarElement.fromDom);
  618. const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  619. const children = element => map$2(element.dom.childNodes, SugarElement.fromDom);
  620. const child$2 = (element, index) => {
  621. const cs = element.dom.childNodes;
  622. return Optional.from(cs[index]).map(SugarElement.fromDom);
  623. };
  624. const firstChild = element => child$2(element, 0);
  625. const spot = (element, offset) => ({
  626. element,
  627. offset
  628. });
  629. const leaf = (element, offset) => {
  630. const cs = children(element);
  631. return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
  632. };
  633. const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  634. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  635. const isSupported = constant$1(supported);
  636. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  637. const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
  638. const isInShadowRoot = e => getShadowRoot(e).isSome();
  639. const getShadowRoot = e => {
  640. const r = getRootNode(e);
  641. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  642. };
  643. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  644. const getOriginalEventTarget = event => {
  645. if (isSupported() && isNonNullable(event.target)) {
  646. const el = SugarElement.fromDom(event.target);
  647. if (isElement$1(el) && isOpenShadowHost(el)) {
  648. if (event.composed && event.composedPath) {
  649. const composedPath = event.composedPath();
  650. if (composedPath) {
  651. return head(composedPath);
  652. }
  653. }
  654. }
  655. }
  656. return Optional.from(event.target);
  657. };
  658. const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
  659. const inBody = element => {
  660. const dom = isText(element) ? element.dom.parentNode : element.dom;
  661. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  662. return false;
  663. }
  664. const doc = dom.ownerDocument;
  665. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  666. };
  667. const body = () => getBody(SugarElement.fromDom(document));
  668. const getBody = doc => {
  669. const b = doc.dom.body;
  670. if (b === null || b === undefined) {
  671. throw new Error('Body is not available yet');
  672. }
  673. return SugarElement.fromDom(b);
  674. };
  675. const rawSet = (dom, key, value) => {
  676. if (isString(value) || isBoolean(value) || isNumber(value)) {
  677. dom.setAttribute(key, value + '');
  678. } else {
  679. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  680. throw new Error('Attribute value was not simple');
  681. }
  682. };
  683. const set$9 = (element, key, value) => {
  684. rawSet(element.dom, key, value);
  685. };
  686. const setAll$1 = (element, attrs) => {
  687. const dom = element.dom;
  688. each(attrs, (v, k) => {
  689. rawSet(dom, k, v);
  690. });
  691. };
  692. const get$f = (element, key) => {
  693. const v = element.dom.getAttribute(key);
  694. return v === null ? undefined : v;
  695. };
  696. const getOpt = (element, key) => Optional.from(get$f(element, key));
  697. const has$1 = (element, key) => {
  698. const dom = element.dom;
  699. return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
  700. };
  701. const remove$7 = (element, key) => {
  702. element.dom.removeAttribute(key);
  703. };
  704. const clone$2 = element => foldl(element.dom.attributes, (acc, attr) => {
  705. acc[attr.name] = attr.value;
  706. return acc;
  707. }, {});
  708. const internalSet = (dom, property, value) => {
  709. if (!isString(value)) {
  710. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  711. throw new Error('CSS value must be a string: ' + value);
  712. }
  713. if (isSupported$1(dom)) {
  714. dom.style.setProperty(property, value);
  715. }
  716. };
  717. const internalRemove = (dom, property) => {
  718. if (isSupported$1(dom)) {
  719. dom.style.removeProperty(property);
  720. }
  721. };
  722. const set$8 = (element, property, value) => {
  723. const dom = element.dom;
  724. internalSet(dom, property, value);
  725. };
  726. const setAll = (element, css) => {
  727. const dom = element.dom;
  728. each(css, (v, k) => {
  729. internalSet(dom, k, v);
  730. });
  731. };
  732. const setOptions = (element, css) => {
  733. const dom = element.dom;
  734. each(css, (v, k) => {
  735. v.fold(() => {
  736. internalRemove(dom, k);
  737. }, value => {
  738. internalSet(dom, k, value);
  739. });
  740. });
  741. };
  742. const get$e = (element, property) => {
  743. const dom = element.dom;
  744. const styles = window.getComputedStyle(dom);
  745. const r = styles.getPropertyValue(property);
  746. return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  747. };
  748. const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : '';
  749. const getRaw = (element, property) => {
  750. const dom = element.dom;
  751. const raw = getUnsafeProperty(dom, property);
  752. return Optional.from(raw).filter(r => r.length > 0);
  753. };
  754. const getAllRaw = element => {
  755. const css = {};
  756. const dom = element.dom;
  757. if (isSupported$1(dom)) {
  758. for (let i = 0; i < dom.style.length; i++) {
  759. const ruleName = dom.style.item(i);
  760. css[ruleName] = dom.style[ruleName];
  761. }
  762. }
  763. return css;
  764. };
  765. const isValidValue$1 = (tag, property, value) => {
  766. const element = SugarElement.fromTag(tag);
  767. set$8(element, property, value);
  768. const style = getRaw(element, property);
  769. return style.isSome();
  770. };
  771. const remove$6 = (element, property) => {
  772. const dom = element.dom;
  773. internalRemove(dom, property);
  774. if (is$1(getOpt(element, 'style').map(trim$1), '')) {
  775. remove$7(element, 'style');
  776. }
  777. };
  778. const reflow = e => e.dom.offsetWidth;
  779. const Dimension = (name, getOffset) => {
  780. const set = (element, h) => {
  781. if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
  782. throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
  783. }
  784. const dom = element.dom;
  785. if (isSupported$1(dom)) {
  786. dom.style[name] = h + 'px';
  787. }
  788. };
  789. const get = element => {
  790. const r = getOffset(element);
  791. if (r <= 0 || r === null) {
  792. const css = get$e(element, name);
  793. return parseFloat(css) || 0;
  794. }
  795. return r;
  796. };
  797. const getOuter = get;
  798. const aggregate = (element, properties) => foldl(properties, (acc, property) => {
  799. const val = get$e(element, property);
  800. const value = val === undefined ? 0 : parseInt(val, 10);
  801. return isNaN(value) ? acc : acc + value;
  802. }, 0);
  803. const max = (element, value, properties) => {
  804. const cumulativeInclusions = aggregate(element, properties);
  805. const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
  806. return absoluteMax;
  807. };
  808. return {
  809. set,
  810. get,
  811. getOuter,
  812. aggregate,
  813. max
  814. };
  815. };
  816. const api$2 = Dimension('height', element => {
  817. const dom = element.dom;
  818. return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
  819. });
  820. const get$d = element => api$2.get(element);
  821. const getOuter$2 = element => api$2.getOuter(element);
  822. const setMax$1 = (element, value) => {
  823. const inclusions = [
  824. 'margin-top',
  825. 'border-top-width',
  826. 'padding-top',
  827. 'padding-bottom',
  828. 'border-bottom-width',
  829. 'margin-bottom'
  830. ];
  831. const absMax = api$2.max(element, value, inclusions);
  832. set$8(element, 'max-height', absMax + 'px');
  833. };
  834. const r$1 = (left, top) => {
  835. const translate = (x, y) => r$1(left + x, top + y);
  836. return {
  837. left,
  838. top,
  839. translate
  840. };
  841. };
  842. const SugarPosition = r$1;
  843. const boxPosition = dom => {
  844. const box = dom.getBoundingClientRect();
  845. return SugarPosition(box.left, box.top);
  846. };
  847. const firstDefinedOrZero = (a, b) => {
  848. if (a !== undefined) {
  849. return a;
  850. } else {
  851. return b !== undefined ? b : 0;
  852. }
  853. };
  854. const absolute$3 = element => {
  855. const doc = element.dom.ownerDocument;
  856. const body = doc.body;
  857. const win = doc.defaultView;
  858. const html = doc.documentElement;
  859. if (body === element.dom) {
  860. return SugarPosition(body.offsetLeft, body.offsetTop);
  861. }
  862. const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
  863. const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
  864. const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
  865. const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
  866. return viewport$1(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
  867. };
  868. const viewport$1 = element => {
  869. const dom = element.dom;
  870. const doc = dom.ownerDocument;
  871. const body = doc.body;
  872. if (body === dom) {
  873. return SugarPosition(body.offsetLeft, body.offsetTop);
  874. }
  875. if (!inBody(element)) {
  876. return SugarPosition(0, 0);
  877. }
  878. return boxPosition(dom);
  879. };
  880. const api$1 = Dimension('width', element => element.dom.offsetWidth);
  881. const set$7 = (element, h) => api$1.set(element, h);
  882. const get$c = element => api$1.get(element);
  883. const getOuter$1 = element => api$1.getOuter(element);
  884. const setMax = (element, value) => {
  885. const inclusions = [
  886. 'margin-left',
  887. 'border-left-width',
  888. 'padding-left',
  889. 'padding-right',
  890. 'border-right-width',
  891. 'margin-right'
  892. ];
  893. const absMax = api$1.max(element, value, inclusions);
  894. set$8(element, 'max-width', absMax + 'px');
  895. };
  896. const cached = f => {
  897. let called = false;
  898. let r;
  899. return (...args) => {
  900. if (!called) {
  901. called = true;
  902. r = f.apply(null, args);
  903. }
  904. return r;
  905. };
  906. };
  907. const DeviceType = (os, browser, userAgent, mediaMatch) => {
  908. const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  909. const isiPhone = os.isiOS() && !isiPad;
  910. const isMobile = os.isiOS() || os.isAndroid();
  911. const isTouch = isMobile || mediaMatch('(pointer:coarse)');
  912. const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  913. const isPhone = isiPhone || isMobile && !isTablet;
  914. const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  915. const isDesktop = !isPhone && !isTablet && !iOSwebview;
  916. return {
  917. isiPad: constant$1(isiPad),
  918. isiPhone: constant$1(isiPhone),
  919. isTablet: constant$1(isTablet),
  920. isPhone: constant$1(isPhone),
  921. isTouch: constant$1(isTouch),
  922. isAndroid: os.isAndroid,
  923. isiOS: os.isiOS,
  924. isWebView: constant$1(iOSwebview),
  925. isDesktop: constant$1(isDesktop)
  926. };
  927. };
  928. const firstMatch = (regexes, s) => {
  929. for (let i = 0; i < regexes.length; i++) {
  930. const x = regexes[i];
  931. if (x.test(s)) {
  932. return x;
  933. }
  934. }
  935. return undefined;
  936. };
  937. const find$3 = (regexes, agent) => {
  938. const r = firstMatch(regexes, agent);
  939. if (!r) {
  940. return {
  941. major: 0,
  942. minor: 0
  943. };
  944. }
  945. const group = i => {
  946. return Number(agent.replace(r, '$' + i));
  947. };
  948. return nu$d(group(1), group(2));
  949. };
  950. const detect$5 = (versionRegexes, agent) => {
  951. const cleanedAgent = String(agent).toLowerCase();
  952. if (versionRegexes.length === 0) {
  953. return unknown$3();
  954. }
  955. return find$3(versionRegexes, cleanedAgent);
  956. };
  957. const unknown$3 = () => {
  958. return nu$d(0, 0);
  959. };
  960. const nu$d = (major, minor) => {
  961. return {
  962. major,
  963. minor
  964. };
  965. };
  966. const Version = {
  967. nu: nu$d,
  968. detect: detect$5,
  969. unknown: unknown$3
  970. };
  971. const detectBrowser$1 = (browsers, userAgentData) => {
  972. return findMap(userAgentData.brands, uaBrand => {
  973. const lcBrand = uaBrand.brand.toLowerCase();
  974. return find$5(browsers, browser => {
  975. var _a;
  976. return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
  977. }).map(info => ({
  978. current: info.name,
  979. version: Version.nu(parseInt(uaBrand.version, 10), 0)
  980. }));
  981. });
  982. };
  983. const detect$4 = (candidates, userAgent) => {
  984. const agent = String(userAgent).toLowerCase();
  985. return find$5(candidates, candidate => {
  986. return candidate.search(agent);
  987. });
  988. };
  989. const detectBrowser = (browsers, userAgent) => {
  990. return detect$4(browsers, userAgent).map(browser => {
  991. const version = Version.detect(browser.versionRegexes, userAgent);
  992. return {
  993. current: browser.name,
  994. version
  995. };
  996. });
  997. };
  998. const detectOs = (oses, userAgent) => {
  999. return detect$4(oses, userAgent).map(os => {
  1000. const version = Version.detect(os.versionRegexes, userAgent);
  1001. return {
  1002. current: os.name,
  1003. version
  1004. };
  1005. });
  1006. };
  1007. const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  1008. const checkContains = target => {
  1009. return uastring => {
  1010. return contains$1(uastring, target);
  1011. };
  1012. };
  1013. const browsers = [
  1014. {
  1015. name: 'Edge',
  1016. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  1017. search: uastring => {
  1018. return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
  1019. }
  1020. },
  1021. {
  1022. name: 'Chromium',
  1023. brand: 'Chromium',
  1024. versionRegexes: [
  1025. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  1026. normalVersionRegex
  1027. ],
  1028. search: uastring => {
  1029. return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
  1030. }
  1031. },
  1032. {
  1033. name: 'IE',
  1034. versionRegexes: [
  1035. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  1036. /.*?rv:([0-9]+)\.([0-9]+).*/
  1037. ],
  1038. search: uastring => {
  1039. return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
  1040. }
  1041. },
  1042. {
  1043. name: 'Opera',
  1044. versionRegexes: [
  1045. normalVersionRegex,
  1046. /.*?opera\/([0-9]+)\.([0-9]+).*/
  1047. ],
  1048. search: checkContains('opera')
  1049. },
  1050. {
  1051. name: 'Firefox',
  1052. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  1053. search: checkContains('firefox')
  1054. },
  1055. {
  1056. name: 'Safari',
  1057. versionRegexes: [
  1058. normalVersionRegex,
  1059. /.*?cpu os ([0-9]+)_([0-9]+).*/
  1060. ],
  1061. search: uastring => {
  1062. return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
  1063. }
  1064. }
  1065. ];
  1066. const oses = [
  1067. {
  1068. name: 'Windows',
  1069. search: checkContains('win'),
  1070. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  1071. },
  1072. {
  1073. name: 'iOS',
  1074. search: uastring => {
  1075. return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
  1076. },
  1077. versionRegexes: [
  1078. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  1079. /.*cpu os ([0-9]+)_([0-9]+).*/,
  1080. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  1081. ]
  1082. },
  1083. {
  1084. name: 'Android',
  1085. search: checkContains('android'),
  1086. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  1087. },
  1088. {
  1089. name: 'macOS',
  1090. search: checkContains('mac os x'),
  1091. versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
  1092. },
  1093. {
  1094. name: 'Linux',
  1095. search: checkContains('linux'),
  1096. versionRegexes: []
  1097. },
  1098. {
  1099. name: 'Solaris',
  1100. search: checkContains('sunos'),
  1101. versionRegexes: []
  1102. },
  1103. {
  1104. name: 'FreeBSD',
  1105. search: checkContains('freebsd'),
  1106. versionRegexes: []
  1107. },
  1108. {
  1109. name: 'ChromeOS',
  1110. search: checkContains('cros'),
  1111. versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
  1112. }
  1113. ];
  1114. const PlatformInfo = {
  1115. browsers: constant$1(browsers),
  1116. oses: constant$1(oses)
  1117. };
  1118. const edge = 'Edge';
  1119. const chromium = 'Chromium';
  1120. const ie = 'IE';
  1121. const opera = 'Opera';
  1122. const firefox = 'Firefox';
  1123. const safari = 'Safari';
  1124. const unknown$2 = () => {
  1125. return nu$c({
  1126. current: undefined,
  1127. version: Version.unknown()
  1128. });
  1129. };
  1130. const nu$c = info => {
  1131. const current = info.current;
  1132. const version = info.version;
  1133. const isBrowser = name => () => current === name;
  1134. return {
  1135. current,
  1136. version,
  1137. isEdge: isBrowser(edge),
  1138. isChromium: isBrowser(chromium),
  1139. isIE: isBrowser(ie),
  1140. isOpera: isBrowser(opera),
  1141. isFirefox: isBrowser(firefox),
  1142. isSafari: isBrowser(safari)
  1143. };
  1144. };
  1145. const Browser = {
  1146. unknown: unknown$2,
  1147. nu: nu$c,
  1148. edge: constant$1(edge),
  1149. chromium: constant$1(chromium),
  1150. ie: constant$1(ie),
  1151. opera: constant$1(opera),
  1152. firefox: constant$1(firefox),
  1153. safari: constant$1(safari)
  1154. };
  1155. const windows = 'Windows';
  1156. const ios = 'iOS';
  1157. const android = 'Android';
  1158. const linux = 'Linux';
  1159. const macos = 'macOS';
  1160. const solaris = 'Solaris';
  1161. const freebsd = 'FreeBSD';
  1162. const chromeos = 'ChromeOS';
  1163. const unknown$1 = () => {
  1164. return nu$b({
  1165. current: undefined,
  1166. version: Version.unknown()
  1167. });
  1168. };
  1169. const nu$b = info => {
  1170. const current = info.current;
  1171. const version = info.version;
  1172. const isOS = name => () => current === name;
  1173. return {
  1174. current,
  1175. version,
  1176. isWindows: isOS(windows),
  1177. isiOS: isOS(ios),
  1178. isAndroid: isOS(android),
  1179. isMacOS: isOS(macos),
  1180. isLinux: isOS(linux),
  1181. isSolaris: isOS(solaris),
  1182. isFreeBSD: isOS(freebsd),
  1183. isChromeOS: isOS(chromeos)
  1184. };
  1185. };
  1186. const OperatingSystem = {
  1187. unknown: unknown$1,
  1188. nu: nu$b,
  1189. windows: constant$1(windows),
  1190. ios: constant$1(ios),
  1191. android: constant$1(android),
  1192. linux: constant$1(linux),
  1193. macos: constant$1(macos),
  1194. solaris: constant$1(solaris),
  1195. freebsd: constant$1(freebsd),
  1196. chromeos: constant$1(chromeos)
  1197. };
  1198. const detect$3 = (userAgent, userAgentDataOpt, mediaMatch) => {
  1199. const browsers = PlatformInfo.browsers();
  1200. const oses = PlatformInfo.oses();
  1201. const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
  1202. const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  1203. const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  1204. return {
  1205. browser,
  1206. os,
  1207. deviceType
  1208. };
  1209. };
  1210. const PlatformDetection = { detect: detect$3 };
  1211. const mediaMatch = query => window.matchMedia(query).matches;
  1212. let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  1213. const detect$2 = () => platform();
  1214. const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
  1215. target,
  1216. x,
  1217. y,
  1218. stop,
  1219. prevent,
  1220. kill,
  1221. raw
  1222. });
  1223. const fromRawEvent$1 = rawEvent => {
  1224. const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
  1225. const stop = () => rawEvent.stopPropagation();
  1226. const prevent = () => rawEvent.preventDefault();
  1227. const kill = compose(prevent, stop);
  1228. return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  1229. };
  1230. const handle = (filter, handler) => rawEvent => {
  1231. if (filter(rawEvent)) {
  1232. handler(fromRawEvent$1(rawEvent));
  1233. }
  1234. };
  1235. const binder = (element, event, filter, handler, useCapture) => {
  1236. const wrapped = handle(filter, handler);
  1237. element.dom.addEventListener(event, wrapped, useCapture);
  1238. return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  1239. };
  1240. const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
  1241. const capture$1 = (element, event, filter, handler) => binder(element, event, filter, handler, true);
  1242. const unbind = (element, event, handler, useCapture) => {
  1243. element.dom.removeEventListener(event, handler, useCapture);
  1244. };
  1245. const before$1 = (marker, element) => {
  1246. const parent$1 = parent(marker);
  1247. parent$1.each(v => {
  1248. v.dom.insertBefore(element.dom, marker.dom);
  1249. });
  1250. };
  1251. const after$2 = (marker, element) => {
  1252. const sibling = nextSibling(marker);
  1253. sibling.fold(() => {
  1254. const parent$1 = parent(marker);
  1255. parent$1.each(v => {
  1256. append$2(v, element);
  1257. });
  1258. }, v => {
  1259. before$1(v, element);
  1260. });
  1261. };
  1262. const prepend$1 = (parent, element) => {
  1263. const firstChild$1 = firstChild(parent);
  1264. firstChild$1.fold(() => {
  1265. append$2(parent, element);
  1266. }, v => {
  1267. parent.dom.insertBefore(element.dom, v.dom);
  1268. });
  1269. };
  1270. const append$2 = (parent, element) => {
  1271. parent.dom.appendChild(element.dom);
  1272. };
  1273. const appendAt = (parent, element, index) => {
  1274. child$2(parent, index).fold(() => {
  1275. append$2(parent, element);
  1276. }, v => {
  1277. before$1(v, element);
  1278. });
  1279. };
  1280. const append$1 = (parent, elements) => {
  1281. each$1(elements, x => {
  1282. append$2(parent, x);
  1283. });
  1284. };
  1285. const empty = element => {
  1286. element.dom.textContent = '';
  1287. each$1(children(element), rogue => {
  1288. remove$5(rogue);
  1289. });
  1290. };
  1291. const remove$5 = element => {
  1292. const dom = element.dom;
  1293. if (dom.parentNode !== null) {
  1294. dom.parentNode.removeChild(dom);
  1295. }
  1296. };
  1297. const get$b = _DOC => {
  1298. const doc = _DOC !== undefined ? _DOC.dom : document;
  1299. const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
  1300. const y = doc.body.scrollTop || doc.documentElement.scrollTop;
  1301. return SugarPosition(x, y);
  1302. };
  1303. const to = (x, y, _DOC) => {
  1304. const doc = _DOC !== undefined ? _DOC.dom : document;
  1305. const win = doc.defaultView;
  1306. if (win) {
  1307. win.scrollTo(x, y);
  1308. }
  1309. };
  1310. const get$a = _win => {
  1311. const win = _win === undefined ? window : _win;
  1312. if (detect$2().browser.isFirefox()) {
  1313. return Optional.none();
  1314. } else {
  1315. return Optional.from(win.visualViewport);
  1316. }
  1317. };
  1318. const bounds$1 = (x, y, width, height) => ({
  1319. x,
  1320. y,
  1321. width,
  1322. height,
  1323. right: x + width,
  1324. bottom: y + height
  1325. });
  1326. const getBounds$3 = _win => {
  1327. const win = _win === undefined ? window : _win;
  1328. const doc = win.document;
  1329. const scroll = get$b(SugarElement.fromDom(doc));
  1330. return get$a(win).fold(() => {
  1331. const html = win.document.documentElement;
  1332. const width = html.clientWidth;
  1333. const height = html.clientHeight;
  1334. return bounds$1(scroll.left, scroll.top, width, height);
  1335. }, visualViewport => bounds$1(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  1336. };
  1337. const getDocument = () => SugarElement.fromDom(document);
  1338. const walkUp = (navigation, doc) => {
  1339. const frame = navigation.view(doc);
  1340. return frame.fold(constant$1([]), f => {
  1341. const parent = navigation.owner(f);
  1342. const rest = walkUp(navigation, parent);
  1343. return [f].concat(rest);
  1344. });
  1345. };
  1346. const pathTo = (element, navigation) => {
  1347. const d = navigation.owner(element);
  1348. const paths = walkUp(navigation, d);
  1349. return Optional.some(paths);
  1350. };
  1351. const view = doc => {
  1352. var _a;
  1353. const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
  1354. return element.map(SugarElement.fromDom);
  1355. };
  1356. const owner$3 = element => owner$4(element);
  1357. var Navigation = /*#__PURE__*/Object.freeze({
  1358. __proto__: null,
  1359. view: view,
  1360. owner: owner$3
  1361. });
  1362. const find$2 = element => {
  1363. const doc = getDocument();
  1364. const scroll = get$b(doc);
  1365. const path = pathTo(element, Navigation);
  1366. return path.fold(curry(absolute$3, element), frames => {
  1367. const offset = viewport$1(element);
  1368. const r = foldr(frames, (b, a) => {
  1369. const loc = viewport$1(a);
  1370. return {
  1371. left: b.left + loc.left,
  1372. top: b.top + loc.top
  1373. };
  1374. }, {
  1375. left: 0,
  1376. top: 0
  1377. });
  1378. return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
  1379. });
  1380. };
  1381. const pointed = (point, width, height) => ({
  1382. point,
  1383. width,
  1384. height
  1385. });
  1386. const rect = (x, y, width, height) => ({
  1387. x,
  1388. y,
  1389. width,
  1390. height
  1391. });
  1392. const bounds = (x, y, width, height) => ({
  1393. x,
  1394. y,
  1395. width,
  1396. height,
  1397. right: x + width,
  1398. bottom: y + height
  1399. });
  1400. const box$1 = element => {
  1401. const xy = absolute$3(element);
  1402. const w = getOuter$1(element);
  1403. const h = getOuter$2(element);
  1404. return bounds(xy.left, xy.top, w, h);
  1405. };
  1406. const absolute$2 = element => {
  1407. const position = find$2(element);
  1408. const width = getOuter$1(element);
  1409. const height = getOuter$2(element);
  1410. return bounds(position.left, position.top, width, height);
  1411. };
  1412. const constrain = (original, constraint) => {
  1413. const left = Math.max(original.x, constraint.x);
  1414. const top = Math.max(original.y, constraint.y);
  1415. const right = Math.min(original.right, constraint.right);
  1416. const bottom = Math.min(original.bottom, constraint.bottom);
  1417. const width = right - left;
  1418. const height = bottom - top;
  1419. return bounds(left, top, width, height);
  1420. };
  1421. const constrainByMany = (original, constraints) => {
  1422. return foldl(constraints, (acc, c) => constrain(acc, c), original);
  1423. };
  1424. const win = () => getBounds$3(window);
  1425. var global$a = tinymce.util.Tools.resolve('tinymce.ThemeManager');
  1426. const value$4 = value => {
  1427. const applyHelper = fn => fn(value);
  1428. const constHelper = constant$1(value);
  1429. const outputHelper = () => output;
  1430. const output = {
  1431. tag: true,
  1432. inner: value,
  1433. fold: (_onError, onValue) => onValue(value),
  1434. isValue: always,
  1435. isError: never,
  1436. map: mapper => Result.value(mapper(value)),
  1437. mapError: outputHelper,
  1438. bind: applyHelper,
  1439. exists: applyHelper,
  1440. forall: applyHelper,
  1441. getOr: constHelper,
  1442. or: outputHelper,
  1443. getOrThunk: constHelper,
  1444. orThunk: outputHelper,
  1445. getOrDie: constHelper,
  1446. each: fn => {
  1447. fn(value);
  1448. },
  1449. toOptional: () => Optional.some(value)
  1450. };
  1451. return output;
  1452. };
  1453. const error$1 = error => {
  1454. const outputHelper = () => output;
  1455. const output = {
  1456. tag: false,
  1457. inner: error,
  1458. fold: (onError, _onValue) => onError(error),
  1459. isValue: never,
  1460. isError: always,
  1461. map: outputHelper,
  1462. mapError: mapper => Result.error(mapper(error)),
  1463. bind: outputHelper,
  1464. exists: never,
  1465. forall: always,
  1466. getOr: identity,
  1467. or: identity,
  1468. getOrThunk: apply$1,
  1469. orThunk: apply$1,
  1470. getOrDie: die(String(error)),
  1471. each: noop,
  1472. toOptional: Optional.none
  1473. };
  1474. return output;
  1475. };
  1476. const fromOption = (optional, err) => optional.fold(() => error$1(err), value$4);
  1477. const Result = {
  1478. value: value$4,
  1479. error: error$1,
  1480. fromOption
  1481. };
  1482. var SimpleResultType;
  1483. (function (SimpleResultType) {
  1484. SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
  1485. SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
  1486. }(SimpleResultType || (SimpleResultType = {})));
  1487. const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
  1488. const partition$2 = results => {
  1489. const values = [];
  1490. const errors = [];
  1491. each$1(results, obj => {
  1492. fold$1(obj, err => errors.push(err), val => values.push(val));
  1493. });
  1494. return {
  1495. values,
  1496. errors
  1497. };
  1498. };
  1499. const mapError = (res, f) => {
  1500. if (res.stype === SimpleResultType.Error) {
  1501. return {
  1502. stype: SimpleResultType.Error,
  1503. serror: f(res.serror)
  1504. };
  1505. } else {
  1506. return res;
  1507. }
  1508. };
  1509. const map = (res, f) => {
  1510. if (res.stype === SimpleResultType.Value) {
  1511. return {
  1512. stype: SimpleResultType.Value,
  1513. svalue: f(res.svalue)
  1514. };
  1515. } else {
  1516. return res;
  1517. }
  1518. };
  1519. const bind$1 = (res, f) => {
  1520. if (res.stype === SimpleResultType.Value) {
  1521. return f(res.svalue);
  1522. } else {
  1523. return res;
  1524. }
  1525. };
  1526. const bindError = (res, f) => {
  1527. if (res.stype === SimpleResultType.Error) {
  1528. return f(res.serror);
  1529. } else {
  1530. return res;
  1531. }
  1532. };
  1533. const svalue = v => ({
  1534. stype: SimpleResultType.Value,
  1535. svalue: v
  1536. });
  1537. const serror = e => ({
  1538. stype: SimpleResultType.Error,
  1539. serror: e
  1540. });
  1541. const toResult$1 = res => fold$1(res, Result.error, Result.value);
  1542. const fromResult$1 = res => res.fold(serror, svalue);
  1543. const SimpleResult = {
  1544. fromResult: fromResult$1,
  1545. toResult: toResult$1,
  1546. svalue,
  1547. partition: partition$2,
  1548. serror,
  1549. bind: bind$1,
  1550. bindError,
  1551. map,
  1552. mapError,
  1553. fold: fold$1
  1554. };
  1555. const field$2 = (key, newKey, presence, prop) => ({
  1556. tag: 'field',
  1557. key,
  1558. newKey,
  1559. presence,
  1560. prop
  1561. });
  1562. const customField$1 = (newKey, instantiator) => ({
  1563. tag: 'custom',
  1564. newKey,
  1565. instantiator
  1566. });
  1567. const fold = (value, ifField, ifCustom) => {
  1568. switch (value.tag) {
  1569. case 'field':
  1570. return ifField(value.key, value.newKey, value.presence, value.prop);
  1571. case 'custom':
  1572. return ifCustom(value.newKey, value.instantiator);
  1573. }
  1574. };
  1575. const shallow$1 = (old, nu) => {
  1576. return nu;
  1577. };
  1578. const deep$1 = (old, nu) => {
  1579. const bothObjects = isPlainObject(old) && isPlainObject(nu);
  1580. return bothObjects ? deepMerge(old, nu) : nu;
  1581. };
  1582. const baseMerge = merger => {
  1583. return (...objects) => {
  1584. if (objects.length === 0) {
  1585. throw new Error(`Can't merge zero objects`);
  1586. }
  1587. const ret = {};
  1588. for (let j = 0; j < objects.length; j++) {
  1589. const curObject = objects[j];
  1590. for (const key in curObject) {
  1591. if (has$2(curObject, key)) {
  1592. ret[key] = merger(ret[key], curObject[key]);
  1593. }
  1594. }
  1595. }
  1596. return ret;
  1597. };
  1598. };
  1599. const deepMerge = baseMerge(deep$1);
  1600. const merge$1 = baseMerge(shallow$1);
  1601. const required$2 = () => ({
  1602. tag: 'required',
  1603. process: {}
  1604. });
  1605. const defaultedThunk = fallbackThunk => ({
  1606. tag: 'defaultedThunk',
  1607. process: fallbackThunk
  1608. });
  1609. const defaulted$1 = fallback => defaultedThunk(constant$1(fallback));
  1610. const asOption = () => ({
  1611. tag: 'option',
  1612. process: {}
  1613. });
  1614. const mergeWithThunk = baseThunk => ({
  1615. tag: 'mergeWithThunk',
  1616. process: baseThunk
  1617. });
  1618. const mergeWith = base => mergeWithThunk(constant$1(base));
  1619. const mergeValues$1 = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values))) : SimpleResult.svalue(base);
  1620. const mergeErrors$1 = errors => compose(SimpleResult.serror, flatten)(errors);
  1621. const consolidateObj = (objects, base) => {
  1622. const partition = SimpleResult.partition(objects);
  1623. return partition.errors.length > 0 ? mergeErrors$1(partition.errors) : mergeValues$1(partition.values, base);
  1624. };
  1625. const consolidateArr = objects => {
  1626. const partitions = SimpleResult.partition(objects);
  1627. return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values);
  1628. };
  1629. const ResultCombine = {
  1630. consolidateObj,
  1631. consolidateArr
  1632. };
  1633. const formatObj = input => {
  1634. return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
  1635. };
  1636. const formatErrors = errors => {
  1637. const es = errors.length > 10 ? errors.slice(0, 10).concat([{
  1638. path: [],
  1639. getErrorInfo: constant$1('... (only showing first ten failures)')
  1640. }]) : errors;
  1641. return map$2(es, e => {
  1642. return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
  1643. });
  1644. };
  1645. const nu$a = (path, getErrorInfo) => {
  1646. return SimpleResult.serror([{
  1647. path,
  1648. getErrorInfo
  1649. }]);
  1650. };
  1651. const missingRequired = (path, key, obj) => nu$a(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
  1652. const missingKey = (path, key) => nu$a(path, () => 'Choice schema did not contain choice key: "' + key + '"');
  1653. const missingBranch = (path, branches, branch) => nu$a(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
  1654. const unsupportedFields = (path, unsupported) => nu$a(path, () => 'There are unsupported fields: [' + unsupported.join(', ') + '] specified');
  1655. const custom = (path, err) => nu$a(path, constant$1(err));
  1656. const value$3 = validator => {
  1657. const extract = (path, val) => {
  1658. return SimpleResult.bindError(validator(val), err => custom(path, err));
  1659. };
  1660. const toString = constant$1('val');
  1661. return {
  1662. extract,
  1663. toString
  1664. };
  1665. };
  1666. const anyValue$1 = value$3(SimpleResult.svalue);
  1667. const requiredAccess = (path, obj, key, bundle) => get$g(obj, key).fold(() => missingRequired(path, key, obj), bundle);
  1668. const fallbackAccess = (obj, key, fallback, bundle) => {
  1669. const v = get$g(obj, key).getOrThunk(() => fallback(obj));
  1670. return bundle(v);
  1671. };
  1672. const optionAccess = (obj, key, bundle) => bundle(get$g(obj, key));
  1673. const optionDefaultedAccess = (obj, key, fallback, bundle) => {
  1674. const opt = get$g(obj, key).map(val => val === true ? fallback(obj) : val);
  1675. return bundle(opt);
  1676. };
  1677. const extractField = (field, path, obj, key, prop) => {
  1678. const bundle = av => prop.extract(path.concat([key]), av);
  1679. const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
  1680. const result = prop.extract(path.concat([key]), ov);
  1681. return SimpleResult.map(result, Optional.some);
  1682. });
  1683. switch (field.tag) {
  1684. case 'required':
  1685. return requiredAccess(path, obj, key, bundle);
  1686. case 'defaultedThunk':
  1687. return fallbackAccess(obj, key, field.process, bundle);
  1688. case 'option':
  1689. return optionAccess(obj, key, bundleAsOption);
  1690. case 'defaultedOptionThunk':
  1691. return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
  1692. case 'mergeWithThunk': {
  1693. return fallbackAccess(obj, key, constant$1({}), v => {
  1694. const result = deepMerge(field.process(obj), v);
  1695. return bundle(result);
  1696. });
  1697. }
  1698. }
  1699. };
  1700. const extractFields = (path, obj, fields) => {
  1701. const success = {};
  1702. const errors = [];
  1703. for (const field of fields) {
  1704. fold(field, (key, newKey, presence, prop) => {
  1705. const result = extractField(presence, path, obj, key, prop);
  1706. SimpleResult.fold(result, err => {
  1707. errors.push(...err);
  1708. }, res => {
  1709. success[newKey] = res;
  1710. });
  1711. }, (newKey, instantiator) => {
  1712. success[newKey] = instantiator(obj);
  1713. });
  1714. }
  1715. return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
  1716. };
  1717. const valueThunk = getDelegate => {
  1718. const extract = (path, val) => getDelegate().extract(path, val);
  1719. const toString = () => getDelegate().toString();
  1720. return {
  1721. extract,
  1722. toString
  1723. };
  1724. };
  1725. const getSetKeys = obj => keys(filter$1(obj, isNonNullable));
  1726. const objOfOnly = fields => {
  1727. const delegate = objOf(fields);
  1728. const fieldNames = foldr(fields, (acc, value) => {
  1729. return fold(value, key => deepMerge(acc, { [key]: true }), constant$1(acc));
  1730. }, {});
  1731. const extract = (path, o) => {
  1732. const keys = isBoolean(o) ? [] : getSetKeys(o);
  1733. const extra = filter$2(keys, k => !hasNonNullableKey(fieldNames, k));
  1734. return extra.length === 0 ? delegate.extract(path, o) : unsupportedFields(path, extra);
  1735. };
  1736. return {
  1737. extract,
  1738. toString: delegate.toString
  1739. };
  1740. };
  1741. const objOf = values => {
  1742. const extract = (path, o) => extractFields(path, o, values);
  1743. const toString = () => {
  1744. const fieldStrings = map$2(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
  1745. return 'obj{\n' + fieldStrings.join('\n') + '}';
  1746. };
  1747. return {
  1748. extract,
  1749. toString
  1750. };
  1751. };
  1752. const arrOf = prop => {
  1753. const extract = (path, array) => {
  1754. const results = map$2(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
  1755. return ResultCombine.consolidateArr(results);
  1756. };
  1757. const toString = () => 'array(' + prop.toString() + ')';
  1758. return {
  1759. extract,
  1760. toString
  1761. };
  1762. };
  1763. const oneOf = (props, rawF) => {
  1764. const f = rawF !== undefined ? rawF : identity;
  1765. const extract = (path, val) => {
  1766. const errors = [];
  1767. for (const prop of props) {
  1768. const res = prop.extract(path, val);
  1769. if (res.stype === SimpleResultType.Value) {
  1770. return {
  1771. stype: SimpleResultType.Value,
  1772. svalue: f(res.svalue)
  1773. };
  1774. }
  1775. errors.push(res);
  1776. }
  1777. return ResultCombine.consolidateArr(errors);
  1778. };
  1779. const toString = () => 'oneOf(' + map$2(props, prop => prop.toString()).join(', ') + ')';
  1780. return {
  1781. extract,
  1782. toString
  1783. };
  1784. };
  1785. const setOf$1 = (validator, prop) => {
  1786. const validateKeys = (path, keys) => arrOf(value$3(validator)).extract(path, keys);
  1787. const extract = (path, o) => {
  1788. const keys$1 = keys(o);
  1789. const validatedKeys = validateKeys(path, keys$1);
  1790. return SimpleResult.bind(validatedKeys, validKeys => {
  1791. const schema = map$2(validKeys, vk => {
  1792. return field$2(vk, vk, required$2(), prop);
  1793. });
  1794. return objOf(schema).extract(path, o);
  1795. });
  1796. };
  1797. const toString = () => 'setOf(' + prop.toString() + ')';
  1798. return {
  1799. extract,
  1800. toString
  1801. };
  1802. };
  1803. const thunk = (_desc, processor) => {
  1804. const getP = cached(processor);
  1805. const extract = (path, val) => getP().extract(path, val);
  1806. const toString = () => getP().toString();
  1807. return {
  1808. extract,
  1809. toString
  1810. };
  1811. };
  1812. const arrOfObj = compose(arrOf, objOf);
  1813. const anyValue = constant$1(anyValue$1);
  1814. const typedValue = (validator, expectedType) => value$3(a => {
  1815. const actualType = typeof a;
  1816. return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
  1817. });
  1818. const number = typedValue(isNumber, 'number');
  1819. const string = typedValue(isString, 'string');
  1820. const boolean = typedValue(isBoolean, 'boolean');
  1821. const functionProcessor = typedValue(isFunction, 'function');
  1822. const isPostMessageable = val => {
  1823. if (Object(val) !== val) {
  1824. return true;
  1825. }
  1826. switch ({}.toString.call(val).slice(8, -1)) {
  1827. case 'Boolean':
  1828. case 'Number':
  1829. case 'String':
  1830. case 'Date':
  1831. case 'RegExp':
  1832. case 'Blob':
  1833. case 'FileList':
  1834. case 'ImageData':
  1835. case 'ImageBitmap':
  1836. case 'ArrayBuffer':
  1837. return true;
  1838. case 'Array':
  1839. case 'Object':
  1840. return Object.keys(val).every(prop => isPostMessageable(val[prop]));
  1841. default:
  1842. return false;
  1843. }
  1844. };
  1845. const postMessageable = value$3(a => {
  1846. if (isPostMessageable(a)) {
  1847. return SimpleResult.svalue(a);
  1848. } else {
  1849. return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
  1850. }
  1851. });
  1852. const chooseFrom = (path, input, branches, ch) => {
  1853. const fields = get$g(branches, ch);
  1854. return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
  1855. };
  1856. const choose$2 = (key, branches) => {
  1857. const extract = (path, input) => {
  1858. const choice = get$g(input, key);
  1859. return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
  1860. };
  1861. const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
  1862. return {
  1863. extract,
  1864. toString
  1865. };
  1866. };
  1867. const arrOfVal = () => arrOf(anyValue$1);
  1868. const valueOf = validator => value$3(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
  1869. const setOf = (validator, prop) => setOf$1(v => SimpleResult.fromResult(validator(v)), prop);
  1870. const extractValue = (label, prop, obj) => {
  1871. const res = prop.extract([label], obj);
  1872. return SimpleResult.mapError(res, errs => ({
  1873. input: obj,
  1874. errors: errs
  1875. }));
  1876. };
  1877. const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
  1878. const getOrDie = extraction => {
  1879. return extraction.fold(errInfo => {
  1880. throw new Error(formatError(errInfo));
  1881. }, identity);
  1882. };
  1883. const asRawOrDie$1 = (label, prop, obj) => getOrDie(asRaw(label, prop, obj));
  1884. const formatError = errInfo => {
  1885. return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
  1886. };
  1887. const choose$1 = (key, branches) => choose$2(key, map$1(branches, objOf));
  1888. const thunkOf = (desc, schema) => thunk(desc, schema);
  1889. const field$1 = field$2;
  1890. const customField = customField$1;
  1891. const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
  1892. const required$1 = key => field$1(key, key, required$2(), anyValue());
  1893. const requiredOf = (key, schema) => field$1(key, key, required$2(), schema);
  1894. const requiredNumber = key => requiredOf(key, number);
  1895. const requiredString = key => requiredOf(key, string);
  1896. const requiredStringEnum = (key, values) => field$1(key, key, required$2(), validateEnum(values));
  1897. const requiredBoolean = key => requiredOf(key, boolean);
  1898. const requiredFunction = key => requiredOf(key, functionProcessor);
  1899. const forbid = (key, message) => field$1(key, key, asOption(), value$3(_v => SimpleResult.serror('The field: ' + key + ' is forbidden. ' + message)));
  1900. const requiredObjOf = (key, objSchema) => field$1(key, key, required$2(), objOf(objSchema));
  1901. const requiredArrayOfObj = (key, objFields) => field$1(key, key, required$2(), arrOfObj(objFields));
  1902. const requiredArrayOf = (key, schema) => field$1(key, key, required$2(), arrOf(schema));
  1903. const option$3 = key => field$1(key, key, asOption(), anyValue());
  1904. const optionOf = (key, schema) => field$1(key, key, asOption(), schema);
  1905. const optionNumber = key => optionOf(key, number);
  1906. const optionString = key => optionOf(key, string);
  1907. const optionStringEnum = (key, values) => optionOf(key, validateEnum(values));
  1908. const optionFunction = key => optionOf(key, functionProcessor);
  1909. const optionArrayOf = (key, schema) => optionOf(key, arrOf(schema));
  1910. const optionObjOf = (key, objSchema) => optionOf(key, objOf(objSchema));
  1911. const optionObjOfOnly = (key, objSchema) => optionOf(key, objOfOnly(objSchema));
  1912. const defaulted = (key, fallback) => field$1(key, key, defaulted$1(fallback), anyValue());
  1913. const defaultedOf = (key, fallback, schema) => field$1(key, key, defaulted$1(fallback), schema);
  1914. const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
  1915. const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
  1916. const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
  1917. const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
  1918. const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
  1919. const defaultedPostMsg = (key, fallback) => defaultedOf(key, fallback, postMessageable);
  1920. const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
  1921. const defaultedObjOf = (key, fallback, objSchema) => defaultedOf(key, fallback, objOf(objSchema));
  1922. const Cell = initial => {
  1923. let value = initial;
  1924. const get = () => {
  1925. return value;
  1926. };
  1927. const set = v => {
  1928. value = v;
  1929. };
  1930. return {
  1931. get,
  1932. set
  1933. };
  1934. };
  1935. const generate$7 = cases => {
  1936. if (!isArray(cases)) {
  1937. throw new Error('cases must be an array');
  1938. }
  1939. if (cases.length === 0) {
  1940. throw new Error('there must be at least one case');
  1941. }
  1942. const constructors = [];
  1943. const adt = {};
  1944. each$1(cases, (acase, count) => {
  1945. const keys$1 = keys(acase);
  1946. if (keys$1.length !== 1) {
  1947. throw new Error('one and only one name per case');
  1948. }
  1949. const key = keys$1[0];
  1950. const value = acase[key];
  1951. if (adt[key] !== undefined) {
  1952. throw new Error('duplicate key detected:' + key);
  1953. } else if (key === 'cata') {
  1954. throw new Error('cannot have a case named cata (sorry)');
  1955. } else if (!isArray(value)) {
  1956. throw new Error('case arguments must be an array');
  1957. }
  1958. constructors.push(key);
  1959. adt[key] = (...args) => {
  1960. const argLength = args.length;
  1961. if (argLength !== value.length) {
  1962. throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
  1963. }
  1964. const match = branches => {
  1965. const branchKeys = keys(branches);
  1966. if (constructors.length !== branchKeys.length) {
  1967. throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
  1968. }
  1969. const allReqd = forall(constructors, reqKey => {
  1970. return contains$2(branchKeys, reqKey);
  1971. });
  1972. if (!allReqd) {
  1973. throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
  1974. }
  1975. return branches[key].apply(null, args);
  1976. };
  1977. return {
  1978. fold: (...foldArgs) => {
  1979. if (foldArgs.length !== cases.length) {
  1980. throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
  1981. }
  1982. const target = foldArgs[count];
  1983. return target.apply(null, args);
  1984. },
  1985. match,
  1986. log: label => {
  1987. console.log(label, {
  1988. constructors,
  1989. constructor: key,
  1990. params: args
  1991. });
  1992. }
  1993. };
  1994. };
  1995. });
  1996. return adt;
  1997. };
  1998. const Adt = { generate: generate$7 };
  1999. Adt.generate([
  2000. {
  2001. bothErrors: [
  2002. 'error1',
  2003. 'error2'
  2004. ]
  2005. },
  2006. {
  2007. firstError: [
  2008. 'error1',
  2009. 'value2'
  2010. ]
  2011. },
  2012. {
  2013. secondError: [
  2014. 'value1',
  2015. 'error2'
  2016. ]
  2017. },
  2018. {
  2019. bothValues: [
  2020. 'value1',
  2021. 'value2'
  2022. ]
  2023. }
  2024. ]);
  2025. const partition$1 = results => {
  2026. const errors = [];
  2027. const values = [];
  2028. each$1(results, result => {
  2029. result.fold(err => {
  2030. errors.push(err);
  2031. }, value => {
  2032. values.push(value);
  2033. });
  2034. });
  2035. return {
  2036. errors,
  2037. values
  2038. };
  2039. };
  2040. const exclude$1 = (obj, fields) => {
  2041. const r = {};
  2042. each(obj, (v, k) => {
  2043. if (!contains$2(fields, k)) {
  2044. r[k] = v;
  2045. }
  2046. });
  2047. return r;
  2048. };
  2049. const wrap$2 = (key, value) => ({ [key]: value });
  2050. const wrapAll$1 = keyvalues => {
  2051. const r = {};
  2052. each$1(keyvalues, kv => {
  2053. r[kv.key] = kv.value;
  2054. });
  2055. return r;
  2056. };
  2057. const exclude = (obj, fields) => exclude$1(obj, fields);
  2058. const wrap$1 = (key, value) => wrap$2(key, value);
  2059. const wrapAll = keyvalues => wrapAll$1(keyvalues);
  2060. const mergeValues = (values, base) => {
  2061. return values.length === 0 ? Result.value(base) : Result.value(deepMerge(base, merge$1.apply(undefined, values)));
  2062. };
  2063. const mergeErrors = errors => Result.error(flatten(errors));
  2064. const consolidate = (objs, base) => {
  2065. const partitions = partition$1(objs);
  2066. return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base);
  2067. };
  2068. const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
  2069. const ancestor$2 = (scope, transform, isRoot) => {
  2070. let element = scope.dom;
  2071. const stop = ensureIsRoot(isRoot);
  2072. while (element.parentNode) {
  2073. element = element.parentNode;
  2074. const el = SugarElement.fromDom(element);
  2075. const transformed = transform(el);
  2076. if (transformed.isSome()) {
  2077. return transformed;
  2078. } else if (stop(el)) {
  2079. break;
  2080. }
  2081. }
  2082. return Optional.none();
  2083. };
  2084. const closest$4 = (scope, transform, isRoot) => {
  2085. const current = transform(scope);
  2086. const stop = ensureIsRoot(isRoot);
  2087. return current.orThunk(() => stop(scope) ? Optional.none() : ancestor$2(scope, transform, stop));
  2088. };
  2089. const isSource = (component, simulatedEvent) => eq(component.element, simulatedEvent.event.target);
  2090. const defaultEventHandler = {
  2091. can: always,
  2092. abort: never,
  2093. run: noop
  2094. };
  2095. const nu$9 = parts => {
  2096. if (!hasNonNullableKey(parts, 'can') && !hasNonNullableKey(parts, 'abort') && !hasNonNullableKey(parts, 'run')) {
  2097. throw new Error('EventHandler defined by: ' + JSON.stringify(parts, null, 2) + ' does not have can, abort, or run!');
  2098. }
  2099. return {
  2100. ...defaultEventHandler,
  2101. ...parts
  2102. };
  2103. };
  2104. const all$2 = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc && f(handler).apply(undefined, args), true);
  2105. const any = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc || f(handler).apply(undefined, args), false);
  2106. const read$2 = handler => isFunction(handler) ? {
  2107. can: always,
  2108. abort: never,
  2109. run: handler
  2110. } : handler;
  2111. const fuse$1 = handlers => {
  2112. const can = all$2(handlers, handler => handler.can);
  2113. const abort = any(handlers, handler => handler.abort);
  2114. const run = (...args) => {
  2115. each$1(handlers, handler => {
  2116. handler.run.apply(undefined, args);
  2117. });
  2118. };
  2119. return {
  2120. can,
  2121. abort,
  2122. run
  2123. };
  2124. };
  2125. const constant = constant$1;
  2126. const touchstart = constant('touchstart');
  2127. const touchmove = constant('touchmove');
  2128. const touchend = constant('touchend');
  2129. const touchcancel = constant('touchcancel');
  2130. const mousedown = constant('mousedown');
  2131. const mousemove = constant('mousemove');
  2132. const mouseout = constant('mouseout');
  2133. const mouseup = constant('mouseup');
  2134. const mouseover = constant('mouseover');
  2135. const focusin = constant('focusin');
  2136. const focusout = constant('focusout');
  2137. const keydown = constant('keydown');
  2138. const keyup = constant('keyup');
  2139. const input = constant('input');
  2140. const change = constant('change');
  2141. const click = constant('click');
  2142. const transitioncancel = constant('transitioncancel');
  2143. const transitionend = constant('transitionend');
  2144. const transitionstart = constant('transitionstart');
  2145. const selectstart = constant('selectstart');
  2146. const prefixName = name => constant$1('alloy.' + name);
  2147. const alloy = { tap: prefixName('tap') };
  2148. const focus$4 = prefixName('focus');
  2149. const postBlur = prefixName('blur.post');
  2150. const postPaste = prefixName('paste.post');
  2151. const receive = prefixName('receive');
  2152. const execute$5 = prefixName('execute');
  2153. const focusItem = prefixName('focus.item');
  2154. const tap = alloy.tap;
  2155. const longpress = prefixName('longpress');
  2156. const sandboxClose = prefixName('sandbox.close');
  2157. const typeaheadCancel = prefixName('typeahead.cancel');
  2158. const systemInit = prefixName('system.init');
  2159. const documentTouchmove = prefixName('system.touchmove');
  2160. const documentTouchend = prefixName('system.touchend');
  2161. const windowScroll = prefixName('system.scroll');
  2162. const windowResize = prefixName('system.resize');
  2163. const attachedToDom = prefixName('system.attached');
  2164. const detachedFromDom = prefixName('system.detached');
  2165. const dismissRequested = prefixName('system.dismissRequested');
  2166. const repositionRequested = prefixName('system.repositionRequested');
  2167. const focusShifted = prefixName('focusmanager.shifted');
  2168. const slotVisibility = prefixName('slotcontainer.visibility');
  2169. const externalElementScroll = prefixName('system.external.element.scroll');
  2170. const changeTab = prefixName('change.tab');
  2171. const dismissTab = prefixName('dismiss.tab');
  2172. const highlight$1 = prefixName('highlight');
  2173. const dehighlight$1 = prefixName('dehighlight');
  2174. const emit = (component, event) => {
  2175. dispatchWith(component, component.element, event, {});
  2176. };
  2177. const emitWith = (component, event, properties) => {
  2178. dispatchWith(component, component.element, event, properties);
  2179. };
  2180. const emitExecute = component => {
  2181. emit(component, execute$5());
  2182. };
  2183. const dispatch = (component, target, event) => {
  2184. dispatchWith(component, target, event, {});
  2185. };
  2186. const dispatchWith = (component, target, event, properties) => {
  2187. const data = {
  2188. target,
  2189. ...properties
  2190. };
  2191. component.getSystem().triggerEvent(event, target, data);
  2192. };
  2193. const retargetAndDispatchWith = (component, target, eventName, properties) => {
  2194. const data = {
  2195. ...properties,
  2196. target
  2197. };
  2198. component.getSystem().triggerEvent(eventName, target, data);
  2199. };
  2200. const dispatchEvent = (component, target, event, simulatedEvent) => {
  2201. component.getSystem().triggerEvent(event, target, simulatedEvent.event);
  2202. };
  2203. const derive$2 = configs => wrapAll(configs);
  2204. const abort = (name, predicate) => {
  2205. return {
  2206. key: name,
  2207. value: nu$9({ abort: predicate })
  2208. };
  2209. };
  2210. const can = (name, predicate) => {
  2211. return {
  2212. key: name,
  2213. value: nu$9({ can: predicate })
  2214. };
  2215. };
  2216. const preventDefault = name => {
  2217. return {
  2218. key: name,
  2219. value: nu$9({
  2220. run: (component, simulatedEvent) => {
  2221. simulatedEvent.event.prevent();
  2222. }
  2223. })
  2224. };
  2225. };
  2226. const run$1 = (name, handler) => {
  2227. return {
  2228. key: name,
  2229. value: nu$9({ run: handler })
  2230. };
  2231. };
  2232. const runActionExtra = (name, action, extra) => {
  2233. return {
  2234. key: name,
  2235. value: nu$9({
  2236. run: (component, simulatedEvent) => {
  2237. action.apply(undefined, [
  2238. component,
  2239. simulatedEvent
  2240. ].concat(extra));
  2241. }
  2242. })
  2243. };
  2244. };
  2245. const runOnName = name => {
  2246. return handler => run$1(name, handler);
  2247. };
  2248. const runOnSourceName = name => {
  2249. return handler => ({
  2250. key: name,
  2251. value: nu$9({
  2252. run: (component, simulatedEvent) => {
  2253. if (isSource(component, simulatedEvent)) {
  2254. handler(component, simulatedEvent);
  2255. }
  2256. }
  2257. })
  2258. });
  2259. };
  2260. const redirectToUid = (name, uid) => {
  2261. return run$1(name, (component, simulatedEvent) => {
  2262. component.getSystem().getByUid(uid).each(redirectee => {
  2263. dispatchEvent(redirectee, redirectee.element, name, simulatedEvent);
  2264. });
  2265. });
  2266. };
  2267. const redirectToPart = (name, detail, partName) => {
  2268. const uid = detail.partUids[partName];
  2269. return redirectToUid(name, uid);
  2270. };
  2271. const runWithTarget = (name, f) => {
  2272. return run$1(name, (component, simulatedEvent) => {
  2273. const ev = simulatedEvent.event;
  2274. const target = component.getSystem().getByDom(ev.target).getOrThunk(() => {
  2275. const closest = closest$4(ev.target, el => component.getSystem().getByDom(el).toOptional(), never);
  2276. return closest.getOr(component);
  2277. });
  2278. f(component, target, simulatedEvent);
  2279. });
  2280. };
  2281. const cutter = name => {
  2282. return run$1(name, (component, simulatedEvent) => {
  2283. simulatedEvent.cut();
  2284. });
  2285. };
  2286. const stopper = name => {
  2287. return run$1(name, (component, simulatedEvent) => {
  2288. simulatedEvent.stop();
  2289. });
  2290. };
  2291. const runOnSource = (name, f) => {
  2292. return runOnSourceName(name)(f);
  2293. };
  2294. const runOnAttached = runOnSourceName(attachedToDom());
  2295. const runOnDetached = runOnSourceName(detachedFromDom());
  2296. const runOnInit = runOnSourceName(systemInit());
  2297. const runOnExecute$1 = runOnName(execute$5());
  2298. const fromHtml$1 = (html, scope) => {
  2299. const doc = scope || document;
  2300. const div = doc.createElement('div');
  2301. div.innerHTML = html;
  2302. return children(SugarElement.fromDom(div));
  2303. };
  2304. const get$9 = element => element.dom.innerHTML;
  2305. const set$6 = (element, content) => {
  2306. const owner = owner$4(element);
  2307. const docDom = owner.dom;
  2308. const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
  2309. const contentElements = fromHtml$1(content, docDom);
  2310. append$1(fragment, contentElements);
  2311. empty(element);
  2312. append$2(element, fragment);
  2313. };
  2314. const getOuter = element => {
  2315. const container = SugarElement.fromTag('div');
  2316. const clone = SugarElement.fromDom(element.dom.cloneNode(true));
  2317. append$2(container, clone);
  2318. return get$9(container);
  2319. };
  2320. const clone$1 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  2321. const shallow = original => clone$1(original, false);
  2322. const deep = original => clone$1(original, true);
  2323. const getHtml = element => {
  2324. if (isShadowRoot(element)) {
  2325. return '#shadow-root';
  2326. } else {
  2327. const clone = shallow(element);
  2328. return getOuter(clone);
  2329. }
  2330. };
  2331. const element = elem => getHtml(elem);
  2332. const isRecursive = (component, originator, target) => eq(originator, component.element) && !eq(originator, target);
  2333. const events$i = derive$2([can(focus$4(), (component, simulatedEvent) => {
  2334. const event = simulatedEvent.event;
  2335. const originator = event.originator;
  2336. const target = event.target;
  2337. if (isRecursive(component, originator, target)) {
  2338. console.warn(focus$4() + ' did not get interpreted by the desired target. ' + '\nOriginator: ' + element(originator) + '\nTarget: ' + element(target) + '\nCheck the ' + focus$4() + ' event handlers');
  2339. return false;
  2340. } else {
  2341. return true;
  2342. }
  2343. })]);
  2344. var DefaultEvents = /*#__PURE__*/Object.freeze({
  2345. __proto__: null,
  2346. events: events$i
  2347. });
  2348. let unique = 0;
  2349. const generate$6 = prefix => {
  2350. const date = new Date();
  2351. const time = date.getTime();
  2352. const random = Math.floor(Math.random() * 1000000000);
  2353. unique++;
  2354. return prefix + '_' + random + unique + String(time);
  2355. };
  2356. const prefix$1 = constant$1('alloy-id-');
  2357. const idAttr$1 = constant$1('data-alloy-id');
  2358. const prefix = prefix$1();
  2359. const idAttr = idAttr$1();
  2360. const write = (label, elem) => {
  2361. const id = generate$6(prefix + label);
  2362. writeOnly(elem, id);
  2363. return id;
  2364. };
  2365. const writeOnly = (elem, uid) => {
  2366. Object.defineProperty(elem.dom, idAttr, {
  2367. value: uid,
  2368. writable: true
  2369. });
  2370. };
  2371. const read$1 = elem => {
  2372. const id = isElement$1(elem) ? elem.dom[idAttr] : null;
  2373. return Optional.from(id);
  2374. };
  2375. const generate$5 = prefix => generate$6(prefix);
  2376. const make$8 = identity;
  2377. const NoContextApi = getComp => {
  2378. const getMessage = event => `The component must be in a context to execute: ${ event }` + (getComp ? '\n' + element(getComp().element) + ' is not in context.' : '');
  2379. const fail = event => () => {
  2380. throw new Error(getMessage(event));
  2381. };
  2382. const warn = event => () => {
  2383. console.warn(getMessage(event));
  2384. };
  2385. return {
  2386. debugInfo: constant$1('fake'),
  2387. triggerEvent: warn('triggerEvent'),
  2388. triggerFocus: warn('triggerFocus'),
  2389. triggerEscape: warn('triggerEscape'),
  2390. broadcast: warn('broadcast'),
  2391. broadcastOn: warn('broadcastOn'),
  2392. broadcastEvent: warn('broadcastEvent'),
  2393. build: fail('build'),
  2394. buildOrPatch: fail('buildOrPatch'),
  2395. addToWorld: fail('addToWorld'),
  2396. removeFromWorld: fail('removeFromWorld'),
  2397. addToGui: fail('addToGui'),
  2398. removeFromGui: fail('removeFromGui'),
  2399. getByUid: fail('getByUid'),
  2400. getByDom: fail('getByDom'),
  2401. isConnected: never
  2402. };
  2403. };
  2404. const singleton$1 = NoContextApi();
  2405. const markAsBehaviourApi = (f, apiName, apiFunction) => {
  2406. const delegate = apiFunction.toString();
  2407. const endIndex = delegate.indexOf(')') + 1;
  2408. const openBracketIndex = delegate.indexOf('(');
  2409. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2410. f.toFunctionAnnotation = () => ({
  2411. name: apiName,
  2412. parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
  2413. });
  2414. return f;
  2415. };
  2416. const cleanParameters = parameters => map$2(parameters, p => endsWith(p, '/*') ? p.substring(0, p.length - '/*'.length) : p);
  2417. const markAsExtraApi = (f, extraName) => {
  2418. const delegate = f.toString();
  2419. const endIndex = delegate.indexOf(')') + 1;
  2420. const openBracketIndex = delegate.indexOf('(');
  2421. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2422. f.toFunctionAnnotation = () => ({
  2423. name: extraName,
  2424. parameters: cleanParameters(parameters)
  2425. });
  2426. return f;
  2427. };
  2428. const markAsSketchApi = (f, apiFunction) => {
  2429. const delegate = apiFunction.toString();
  2430. const endIndex = delegate.indexOf(')') + 1;
  2431. const openBracketIndex = delegate.indexOf('(');
  2432. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2433. f.toFunctionAnnotation = () => ({
  2434. name: 'OVERRIDE',
  2435. parameters: cleanParameters(parameters.slice(1))
  2436. });
  2437. return f;
  2438. };
  2439. const premadeTag = generate$6('alloy-premade');
  2440. const premade$1 = comp => {
  2441. Object.defineProperty(comp.element.dom, premadeTag, {
  2442. value: comp.uid,
  2443. writable: true
  2444. });
  2445. return wrap$1(premadeTag, comp);
  2446. };
  2447. const isPremade = element => has$2(element.dom, premadeTag);
  2448. const getPremade = spec => get$g(spec, premadeTag);
  2449. const makeApi = f => markAsSketchApi((component, ...rest) => f(component.getApis(), component, ...rest), f);
  2450. const NoState = { init: () => nu$8({ readState: constant$1('No State required') }) };
  2451. const nu$8 = spec => spec;
  2452. const generateFrom$1 = (spec, all) => {
  2453. const schema = map$2(all, a => optionObjOf(a.name(), [
  2454. required$1('config'),
  2455. defaulted('state', NoState)
  2456. ]));
  2457. const validated = asRaw('component.behaviours', objOf(schema), spec.behaviours).fold(errInfo => {
  2458. throw new Error(formatError(errInfo) + '\nComplete spec:\n' + JSON.stringify(spec, null, 2));
  2459. }, identity);
  2460. return {
  2461. list: all,
  2462. data: map$1(validated, optBlobThunk => {
  2463. const output = optBlobThunk.map(blob => ({
  2464. config: blob.config,
  2465. state: blob.state.init(blob.config)
  2466. }));
  2467. return constant$1(output);
  2468. })
  2469. };
  2470. };
  2471. const getBehaviours$3 = bData => bData.list;
  2472. const getData$2 = bData => bData.data;
  2473. const byInnerKey = (data, tuple) => {
  2474. const r = {};
  2475. each(data, (detail, key) => {
  2476. each(detail, (value, indexKey) => {
  2477. const chain = get$g(r, indexKey).getOr([]);
  2478. r[indexKey] = chain.concat([tuple(key, value)]);
  2479. });
  2480. });
  2481. return r;
  2482. };
  2483. const nu$7 = s => ({
  2484. classes: isUndefined(s.classes) ? [] : s.classes,
  2485. attributes: isUndefined(s.attributes) ? {} : s.attributes,
  2486. styles: isUndefined(s.styles) ? {} : s.styles
  2487. });
  2488. const merge = (defnA, mod) => ({
  2489. ...defnA,
  2490. attributes: {
  2491. ...defnA.attributes,
  2492. ...mod.attributes
  2493. },
  2494. styles: {
  2495. ...defnA.styles,
  2496. ...mod.styles
  2497. },
  2498. classes: defnA.classes.concat(mod.classes)
  2499. });
  2500. const combine$2 = (info, baseMod, behaviours, base) => {
  2501. const modsByBehaviour = { ...baseMod };
  2502. each$1(behaviours, behaviour => {
  2503. modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base);
  2504. });
  2505. const byAspect = byInnerKey(modsByBehaviour, (name, modification) => ({
  2506. name,
  2507. modification
  2508. }));
  2509. const combineObjects = objects => foldr(objects, (b, a) => ({
  2510. ...a.modification,
  2511. ...b
  2512. }), {});
  2513. const combinedClasses = foldr(byAspect.classes, (b, a) => a.modification.concat(b), []);
  2514. const combinedAttributes = combineObjects(byAspect.attributes);
  2515. const combinedStyles = combineObjects(byAspect.styles);
  2516. return nu$7({
  2517. classes: combinedClasses,
  2518. attributes: combinedAttributes,
  2519. styles: combinedStyles
  2520. });
  2521. };
  2522. const sortKeys = (label, keyName, array, order) => {
  2523. try {
  2524. const sorted = sort(array, (a, b) => {
  2525. const aKey = a[keyName];
  2526. const bKey = b[keyName];
  2527. const aIndex = order.indexOf(aKey);
  2528. const bIndex = order.indexOf(bKey);
  2529. if (aIndex === -1) {
  2530. throw new Error('The ordering for ' + label + ' does not have an entry for ' + aKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
  2531. }
  2532. if (bIndex === -1) {
  2533. throw new Error('The ordering for ' + label + ' does not have an entry for ' + bKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
  2534. }
  2535. if (aIndex < bIndex) {
  2536. return -1;
  2537. } else if (bIndex < aIndex) {
  2538. return 1;
  2539. } else {
  2540. return 0;
  2541. }
  2542. });
  2543. return Result.value(sorted);
  2544. } catch (err) {
  2545. return Result.error([err]);
  2546. }
  2547. };
  2548. const uncurried = (handler, purpose) => ({
  2549. handler,
  2550. purpose
  2551. });
  2552. const curried = (handler, purpose) => ({
  2553. cHandler: handler,
  2554. purpose
  2555. });
  2556. const curryArgs = (descHandler, extraArgs) => curried(curry.apply(undefined, [descHandler.handler].concat(extraArgs)), descHandler.purpose);
  2557. const getCurried = descHandler => descHandler.cHandler;
  2558. const behaviourTuple = (name, handler) => ({
  2559. name,
  2560. handler
  2561. });
  2562. const nameToHandlers = (behaviours, info) => {
  2563. const r = {};
  2564. each$1(behaviours, behaviour => {
  2565. r[behaviour.name()] = behaviour.handlers(info);
  2566. });
  2567. return r;
  2568. };
  2569. const groupByEvents = (info, behaviours, base) => {
  2570. const behaviourEvents = {
  2571. ...base,
  2572. ...nameToHandlers(behaviours, info)
  2573. };
  2574. return byInnerKey(behaviourEvents, behaviourTuple);
  2575. };
  2576. const combine$1 = (info, eventOrder, behaviours, base) => {
  2577. const byEventName = groupByEvents(info, behaviours, base);
  2578. return combineGroups(byEventName, eventOrder);
  2579. };
  2580. const assemble = rawHandler => {
  2581. const handler = read$2(rawHandler);
  2582. return (component, simulatedEvent, ...rest) => {
  2583. const args = [
  2584. component,
  2585. simulatedEvent
  2586. ].concat(rest);
  2587. if (handler.abort.apply(undefined, args)) {
  2588. simulatedEvent.stop();
  2589. } else if (handler.can.apply(undefined, args)) {
  2590. handler.run.apply(undefined, args);
  2591. }
  2592. };
  2593. };
  2594. const missingOrderError = (eventName, tuples) => Result.error(['The event (' + eventName + ') has more than one behaviour that listens to it.\nWhen this occurs, you must ' + 'specify an event ordering for the behaviours in your spec (e.g. [ "listing", "toggling" ]).\nThe behaviours that ' + 'can trigger it are: ' + JSON.stringify(map$2(tuples, c => c.name), null, 2)]);
  2595. const fuse = (tuples, eventOrder, eventName) => {
  2596. const order = eventOrder[eventName];
  2597. if (!order) {
  2598. return missingOrderError(eventName, tuples);
  2599. } else {
  2600. return sortKeys('Event: ' + eventName, 'name', tuples, order).map(sortedTuples => {
  2601. const handlers = map$2(sortedTuples, tuple => tuple.handler);
  2602. return fuse$1(handlers);
  2603. });
  2604. }
  2605. };
  2606. const combineGroups = (byEventName, eventOrder) => {
  2607. const r = mapToArray(byEventName, (tuples, eventName) => {
  2608. const combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName);
  2609. return combined.map(handler => {
  2610. const assembled = assemble(handler);
  2611. const purpose = tuples.length > 1 ? filter$2(eventOrder[eventName], o => exists(tuples, t => t.name === o)).join(' > ') : tuples[0].name;
  2612. return wrap$1(eventName, uncurried(assembled, purpose));
  2613. });
  2614. });
  2615. return consolidate(r, {});
  2616. };
  2617. const baseBehaviour = 'alloy.base.behaviour';
  2618. const schema$z = objOf([
  2619. field$1('dom', 'dom', required$2(), objOf([
  2620. required$1('tag'),
  2621. defaulted('styles', {}),
  2622. defaulted('classes', []),
  2623. defaulted('attributes', {}),
  2624. option$3('value'),
  2625. option$3('innerHtml')
  2626. ])),
  2627. required$1('components'),
  2628. required$1('uid'),
  2629. defaulted('events', {}),
  2630. defaulted('apis', {}),
  2631. field$1('eventOrder', 'eventOrder', mergeWith({
  2632. [execute$5()]: [
  2633. 'disabling',
  2634. baseBehaviour,
  2635. 'toggling',
  2636. 'typeaheadevents'
  2637. ],
  2638. [focus$4()]: [
  2639. baseBehaviour,
  2640. 'focusing',
  2641. 'keying'
  2642. ],
  2643. [systemInit()]: [
  2644. baseBehaviour,
  2645. 'disabling',
  2646. 'toggling',
  2647. 'representing'
  2648. ],
  2649. [input()]: [
  2650. baseBehaviour,
  2651. 'representing',
  2652. 'streaming',
  2653. 'invalidating'
  2654. ],
  2655. [detachedFromDom()]: [
  2656. baseBehaviour,
  2657. 'representing',
  2658. 'item-events',
  2659. 'tooltipping'
  2660. ],
  2661. [mousedown()]: [
  2662. 'focusing',
  2663. baseBehaviour,
  2664. 'item-type-events'
  2665. ],
  2666. [touchstart()]: [
  2667. 'focusing',
  2668. baseBehaviour,
  2669. 'item-type-events'
  2670. ],
  2671. [mouseover()]: [
  2672. 'item-type-events',
  2673. 'tooltipping'
  2674. ],
  2675. [receive()]: [
  2676. 'receiving',
  2677. 'reflecting',
  2678. 'tooltipping'
  2679. ]
  2680. }), anyValue()),
  2681. option$3('domModification')
  2682. ]);
  2683. const toInfo = spec => asRaw('custom.definition', schema$z, spec);
  2684. const toDefinition = detail => ({
  2685. ...detail.dom,
  2686. uid: detail.uid,
  2687. domChildren: map$2(detail.components, comp => comp.element)
  2688. });
  2689. const toModification = detail => detail.domModification.fold(() => nu$7({}), nu$7);
  2690. const toEvents = info => info.events;
  2691. const read = (element, attr) => {
  2692. const value = get$f(element, attr);
  2693. return value === undefined || value === '' ? [] : value.split(' ');
  2694. };
  2695. const add$4 = (element, attr, id) => {
  2696. const old = read(element, attr);
  2697. const nu = old.concat([id]);
  2698. set$9(element, attr, nu.join(' '));
  2699. return true;
  2700. };
  2701. const remove$4 = (element, attr, id) => {
  2702. const nu = filter$2(read(element, attr), v => v !== id);
  2703. if (nu.length > 0) {
  2704. set$9(element, attr, nu.join(' '));
  2705. } else {
  2706. remove$7(element, attr);
  2707. }
  2708. return false;
  2709. };
  2710. const supports = element => element.dom.classList !== undefined;
  2711. const get$8 = element => read(element, 'class');
  2712. const add$3 = (element, clazz) => add$4(element, 'class', clazz);
  2713. const remove$3 = (element, clazz) => remove$4(element, 'class', clazz);
  2714. const toggle$5 = (element, clazz) => {
  2715. if (contains$2(get$8(element), clazz)) {
  2716. return remove$3(element, clazz);
  2717. } else {
  2718. return add$3(element, clazz);
  2719. }
  2720. };
  2721. const add$2 = (element, clazz) => {
  2722. if (supports(element)) {
  2723. element.dom.classList.add(clazz);
  2724. } else {
  2725. add$3(element, clazz);
  2726. }
  2727. };
  2728. const cleanClass = element => {
  2729. const classList = supports(element) ? element.dom.classList : get$8(element);
  2730. if (classList.length === 0) {
  2731. remove$7(element, 'class');
  2732. }
  2733. };
  2734. const remove$2 = (element, clazz) => {
  2735. if (supports(element)) {
  2736. const classList = element.dom.classList;
  2737. classList.remove(clazz);
  2738. } else {
  2739. remove$3(element, clazz);
  2740. }
  2741. cleanClass(element);
  2742. };
  2743. const toggle$4 = (element, clazz) => {
  2744. const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$5(element, clazz);
  2745. cleanClass(element);
  2746. return result;
  2747. };
  2748. const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
  2749. const add$1 = (element, classes) => {
  2750. each$1(classes, x => {
  2751. add$2(element, x);
  2752. });
  2753. };
  2754. const remove$1 = (element, classes) => {
  2755. each$1(classes, x => {
  2756. remove$2(element, x);
  2757. });
  2758. };
  2759. const toggle$3 = (element, classes) => {
  2760. each$1(classes, x => {
  2761. toggle$4(element, x);
  2762. });
  2763. };
  2764. const hasAll = (element, classes) => forall(classes, clazz => has(element, clazz));
  2765. const getNative = element => {
  2766. const classList = element.dom.classList;
  2767. const r = new Array(classList.length);
  2768. for (let i = 0; i < classList.length; i++) {
  2769. const item = classList.item(i);
  2770. if (item !== null) {
  2771. r[i] = item;
  2772. }
  2773. }
  2774. return r;
  2775. };
  2776. const get$7 = element => supports(element) ? getNative(element) : get$8(element);
  2777. const get$6 = element => element.dom.value;
  2778. const set$5 = (element, value) => {
  2779. if (value === undefined) {
  2780. throw new Error('Value.set was undefined');
  2781. }
  2782. element.dom.value = value;
  2783. };
  2784. const determineObsoleted = (parent, index, oldObsoleted) => {
  2785. const newObsoleted = child$2(parent, index);
  2786. return newObsoleted.map(newObs => {
  2787. const elemChanged = oldObsoleted.exists(o => !eq(o, newObs));
  2788. if (elemChanged) {
  2789. const oldTag = oldObsoleted.map(name$3).getOr('span');
  2790. const marker = SugarElement.fromTag(oldTag);
  2791. before$1(newObs, marker);
  2792. return marker;
  2793. } else {
  2794. return newObs;
  2795. }
  2796. });
  2797. };
  2798. const ensureInDom = (parent, child, obsoleted) => {
  2799. obsoleted.fold(() => append$2(parent, child), obs => {
  2800. if (!eq(obs, child)) {
  2801. before$1(obs, child);
  2802. remove$5(obs);
  2803. }
  2804. });
  2805. };
  2806. const patchChildrenWith = (parent, nu, f) => {
  2807. const builtChildren = map$2(nu, f);
  2808. const currentChildren = children(parent);
  2809. each$1(currentChildren.slice(builtChildren.length), remove$5);
  2810. return builtChildren;
  2811. };
  2812. const patchSpecChild = (parent, index, spec, build) => {
  2813. const oldObsoleted = child$2(parent, index);
  2814. const childComp = build(spec, oldObsoleted);
  2815. const obsoleted = determineObsoleted(parent, index, oldObsoleted);
  2816. ensureInDom(parent, childComp.element, obsoleted);
  2817. return childComp;
  2818. };
  2819. const patchSpecChildren = (parent, specs, build) => patchChildrenWith(parent, specs, (spec, index) => patchSpecChild(parent, index, spec, build));
  2820. const patchDomChildren = (parent, nodes) => patchChildrenWith(parent, nodes, (node, index) => {
  2821. const optObsoleted = child$2(parent, index);
  2822. ensureInDom(parent, node, optObsoleted);
  2823. return node;
  2824. });
  2825. const diffKeyValueSet = (newObj, oldObj) => {
  2826. const newKeys = keys(newObj);
  2827. const oldKeys = keys(oldObj);
  2828. const toRemove = difference(oldKeys, newKeys);
  2829. const toSet = bifilter(newObj, (v, k) => {
  2830. return !has$2(oldObj, k) || v !== oldObj[k];
  2831. }).t;
  2832. return {
  2833. toRemove,
  2834. toSet
  2835. };
  2836. };
  2837. const reconcileToDom = (definition, obsoleted) => {
  2838. const {
  2839. class: clazz,
  2840. style,
  2841. ...existingAttributes
  2842. } = clone$2(obsoleted);
  2843. const {
  2844. toSet: attrsToSet,
  2845. toRemove: attrsToRemove
  2846. } = diffKeyValueSet(definition.attributes, existingAttributes);
  2847. const updateAttrs = () => {
  2848. each$1(attrsToRemove, a => remove$7(obsoleted, a));
  2849. setAll$1(obsoleted, attrsToSet);
  2850. };
  2851. const existingStyles = getAllRaw(obsoleted);
  2852. const {
  2853. toSet: stylesToSet,
  2854. toRemove: stylesToRemove
  2855. } = diffKeyValueSet(definition.styles, existingStyles);
  2856. const updateStyles = () => {
  2857. each$1(stylesToRemove, s => remove$6(obsoleted, s));
  2858. setAll(obsoleted, stylesToSet);
  2859. };
  2860. const existingClasses = get$7(obsoleted);
  2861. const classesToRemove = difference(existingClasses, definition.classes);
  2862. const classesToAdd = difference(definition.classes, existingClasses);
  2863. const updateClasses = () => {
  2864. add$1(obsoleted, classesToAdd);
  2865. remove$1(obsoleted, classesToRemove);
  2866. };
  2867. const updateHtml = html => {
  2868. set$6(obsoleted, html);
  2869. };
  2870. const updateChildren = () => {
  2871. const children = definition.domChildren;
  2872. patchDomChildren(obsoleted, children);
  2873. };
  2874. const updateValue = () => {
  2875. const valueElement = obsoleted;
  2876. const value = definition.value.getOrUndefined();
  2877. if (value !== get$6(valueElement)) {
  2878. set$5(valueElement, value !== null && value !== void 0 ? value : '');
  2879. }
  2880. };
  2881. updateAttrs();
  2882. updateClasses();
  2883. updateStyles();
  2884. definition.innerHtml.fold(updateChildren, updateHtml);
  2885. updateValue();
  2886. return obsoleted;
  2887. };
  2888. const introduceToDom = definition => {
  2889. const subject = SugarElement.fromTag(definition.tag);
  2890. setAll$1(subject, definition.attributes);
  2891. add$1(subject, definition.classes);
  2892. setAll(subject, definition.styles);
  2893. definition.innerHtml.each(html => set$6(subject, html));
  2894. const children = definition.domChildren;
  2895. append$1(subject, children);
  2896. definition.value.each(value => {
  2897. set$5(subject, value);
  2898. });
  2899. return subject;
  2900. };
  2901. const attemptPatch = (definition, obsoleted) => {
  2902. try {
  2903. const e = reconcileToDom(definition, obsoleted);
  2904. return Optional.some(e);
  2905. } catch (err) {
  2906. return Optional.none();
  2907. }
  2908. };
  2909. const hasMixedChildren = definition => definition.innerHtml.isSome() && definition.domChildren.length > 0;
  2910. const renderToDom = (definition, optObsoleted) => {
  2911. const canBePatched = candidate => name$3(candidate) === definition.tag && !hasMixedChildren(definition) && !isPremade(candidate);
  2912. const elem = optObsoleted.filter(canBePatched).bind(obsoleted => attemptPatch(definition, obsoleted)).getOrThunk(() => introduceToDom(definition));
  2913. writeOnly(elem, definition.uid);
  2914. return elem;
  2915. };
  2916. const getBehaviours$2 = spec => {
  2917. const behaviours = get$g(spec, 'behaviours').getOr({});
  2918. return bind$3(keys(behaviours), name => {
  2919. const behaviour = behaviours[name];
  2920. return isNonNullable(behaviour) ? [behaviour.me] : [];
  2921. });
  2922. };
  2923. const generateFrom = (spec, all) => generateFrom$1(spec, all);
  2924. const generate$4 = spec => {
  2925. const all = getBehaviours$2(spec);
  2926. return generateFrom(spec, all);
  2927. };
  2928. const getDomDefinition = (info, bList, bData) => {
  2929. const definition = toDefinition(info);
  2930. const infoModification = toModification(info);
  2931. const baseModification = { 'alloy.base.modification': infoModification };
  2932. const modification = bList.length > 0 ? combine$2(bData, baseModification, bList, definition) : infoModification;
  2933. return merge(definition, modification);
  2934. };
  2935. const getEvents = (info, bList, bData) => {
  2936. const baseEvents = { 'alloy.base.behaviour': toEvents(info) };
  2937. return combine$1(bData, info.eventOrder, bList, baseEvents).getOrDie();
  2938. };
  2939. const build$2 = (spec, obsoleted) => {
  2940. const getMe = () => me;
  2941. const systemApi = Cell(singleton$1);
  2942. const info = getOrDie(toInfo(spec));
  2943. const bBlob = generate$4(spec);
  2944. const bList = getBehaviours$3(bBlob);
  2945. const bData = getData$2(bBlob);
  2946. const modDefinition = getDomDefinition(info, bList, bData);
  2947. const item = renderToDom(modDefinition, obsoleted);
  2948. const events = getEvents(info, bList, bData);
  2949. const subcomponents = Cell(info.components);
  2950. const connect = newApi => {
  2951. systemApi.set(newApi);
  2952. };
  2953. const disconnect = () => {
  2954. systemApi.set(NoContextApi(getMe));
  2955. };
  2956. const syncComponents = () => {
  2957. const children$1 = children(item);
  2958. const subs = bind$3(children$1, child => systemApi.get().getByDom(child).fold(() => [], pure$2));
  2959. subcomponents.set(subs);
  2960. };
  2961. const config = behaviour => {
  2962. const b = bData;
  2963. const f = isFunction(b[behaviour.name()]) ? b[behaviour.name()] : () => {
  2964. throw new Error('Could not find ' + behaviour.name() + ' in ' + JSON.stringify(spec, null, 2));
  2965. };
  2966. return f();
  2967. };
  2968. const hasConfigured = behaviour => isFunction(bData[behaviour.name()]);
  2969. const getApis = () => info.apis;
  2970. const readState = behaviourName => bData[behaviourName]().map(b => b.state.readState()).getOr('not enabled');
  2971. const me = {
  2972. uid: spec.uid,
  2973. getSystem: systemApi.get,
  2974. config,
  2975. hasConfigured,
  2976. spec,
  2977. readState,
  2978. getApis,
  2979. connect,
  2980. disconnect,
  2981. element: item,
  2982. syncComponents,
  2983. components: subcomponents.get,
  2984. events
  2985. };
  2986. return me;
  2987. };
  2988. const buildSubcomponents = (spec, obsoleted) => {
  2989. const components = get$g(spec, 'components').getOr([]);
  2990. return obsoleted.fold(() => map$2(components, build$1), obs => map$2(components, (c, i) => {
  2991. return buildOrPatch(c, child$2(obs, i));
  2992. }));
  2993. };
  2994. const buildFromSpec = (userSpec, obsoleted) => {
  2995. const {
  2996. events: specEvents,
  2997. ...spec
  2998. } = make$8(userSpec);
  2999. const components = buildSubcomponents(spec, obsoleted);
  3000. const completeSpec = {
  3001. ...spec,
  3002. events: {
  3003. ...DefaultEvents,
  3004. ...specEvents
  3005. },
  3006. components
  3007. };
  3008. return Result.value(build$2(completeSpec, obsoleted));
  3009. };
  3010. const text$2 = textContent => {
  3011. const element = SugarElement.fromText(textContent);
  3012. return external$1({ element });
  3013. };
  3014. const external$1 = spec => {
  3015. const extSpec = asRawOrDie$1('external.component', objOfOnly([
  3016. required$1('element'),
  3017. option$3('uid')
  3018. ]), spec);
  3019. const systemApi = Cell(NoContextApi());
  3020. const connect = newApi => {
  3021. systemApi.set(newApi);
  3022. };
  3023. const disconnect = () => {
  3024. systemApi.set(NoContextApi(() => me));
  3025. };
  3026. const uid = extSpec.uid.getOrThunk(() => generate$5('external'));
  3027. writeOnly(extSpec.element, uid);
  3028. const me = {
  3029. uid,
  3030. getSystem: systemApi.get,
  3031. config: Optional.none,
  3032. hasConfigured: never,
  3033. connect,
  3034. disconnect,
  3035. getApis: () => ({}),
  3036. element: extSpec.element,
  3037. spec,
  3038. readState: constant$1('No state'),
  3039. syncComponents: noop,
  3040. components: constant$1([]),
  3041. events: {}
  3042. };
  3043. return premade$1(me);
  3044. };
  3045. const uids = generate$5;
  3046. const isSketchSpec$1 = spec => has$2(spec, 'uid');
  3047. const buildOrPatch = (spec, obsoleted) => getPremade(spec).getOrThunk(() => {
  3048. const userSpecWithUid = isSketchSpec$1(spec) ? spec : {
  3049. uid: uids(''),
  3050. ...spec
  3051. };
  3052. return buildFromSpec(userSpecWithUid, obsoleted).getOrDie();
  3053. });
  3054. const build$1 = spec => buildOrPatch(spec, Optional.none());
  3055. const premade = premade$1;
  3056. var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
  3057. if (is(scope, a)) {
  3058. return Optional.some(scope);
  3059. } else if (isFunction(isRoot) && isRoot(scope)) {
  3060. return Optional.none();
  3061. } else {
  3062. return ancestor(scope, a, isRoot);
  3063. }
  3064. };
  3065. const ancestor$1 = (scope, predicate, isRoot) => {
  3066. let element = scope.dom;
  3067. const stop = isFunction(isRoot) ? isRoot : never;
  3068. while (element.parentNode) {
  3069. element = element.parentNode;
  3070. const el = SugarElement.fromDom(element);
  3071. if (predicate(el)) {
  3072. return Optional.some(el);
  3073. } else if (stop(el)) {
  3074. break;
  3075. }
  3076. }
  3077. return Optional.none();
  3078. };
  3079. const closest$3 = (scope, predicate, isRoot) => {
  3080. const is = (s, test) => test(s);
  3081. return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
  3082. };
  3083. const child$1 = (scope, predicate) => {
  3084. const pred = node => predicate(SugarElement.fromDom(node));
  3085. const result = find$5(scope.dom.childNodes, pred);
  3086. return result.map(SugarElement.fromDom);
  3087. };
  3088. const descendant$1 = (scope, predicate) => {
  3089. const descend = node => {
  3090. for (let i = 0; i < node.childNodes.length; i++) {
  3091. const child = SugarElement.fromDom(node.childNodes[i]);
  3092. if (predicate(child)) {
  3093. return Optional.some(child);
  3094. }
  3095. const res = descend(node.childNodes[i]);
  3096. if (res.isSome()) {
  3097. return res;
  3098. }
  3099. }
  3100. return Optional.none();
  3101. };
  3102. return descend(scope.dom);
  3103. };
  3104. const closest$2 = (scope, predicate, isRoot) => closest$3(scope, predicate, isRoot).isSome();
  3105. const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
  3106. const child = (scope, selector) => child$1(scope, e => is(e, selector));
  3107. const descendant = (scope, selector) => one(selector, scope);
  3108. const closest$1 = (scope, selector, isRoot) => {
  3109. const is$1 = (element, selector) => is(element, selector);
  3110. return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
  3111. };
  3112. const attribute = 'aria-controls';
  3113. const find$1 = queryElem => {
  3114. const dependent = closest$3(queryElem, elem => {
  3115. if (!isElement$1(elem)) {
  3116. return false;
  3117. }
  3118. const id = get$f(elem, 'id');
  3119. return id !== undefined && id.indexOf(attribute) > -1;
  3120. });
  3121. return dependent.bind(dep => {
  3122. const id = get$f(dep, 'id');
  3123. const dos = getRootNode(dep);
  3124. return descendant(dos, `[${ attribute }="${ id }"]`);
  3125. });
  3126. };
  3127. const manager = () => {
  3128. const ariaId = generate$6(attribute);
  3129. const link = elem => {
  3130. set$9(elem, attribute, ariaId);
  3131. };
  3132. const unlink = elem => {
  3133. remove$7(elem, attribute);
  3134. };
  3135. return {
  3136. id: ariaId,
  3137. link,
  3138. unlink
  3139. };
  3140. };
  3141. const isAriaPartOf = (component, queryElem) => find$1(queryElem).exists(owner => isPartOf$1(component, owner));
  3142. const isPartOf$1 = (component, queryElem) => closest$2(queryElem, el => eq(el, component.element), never) || isAriaPartOf(component, queryElem);
  3143. const unknown = 'unknown';
  3144. var EventConfiguration;
  3145. (function (EventConfiguration) {
  3146. EventConfiguration[EventConfiguration['STOP'] = 0] = 'STOP';
  3147. EventConfiguration[EventConfiguration['NORMAL'] = 1] = 'NORMAL';
  3148. EventConfiguration[EventConfiguration['LOGGING'] = 2] = 'LOGGING';
  3149. }(EventConfiguration || (EventConfiguration = {})));
  3150. const eventConfig = Cell({});
  3151. const makeEventLogger = (eventName, initialTarget) => {
  3152. const sequence = [];
  3153. const startTime = new Date().getTime();
  3154. return {
  3155. logEventCut: (_name, target, purpose) => {
  3156. sequence.push({
  3157. outcome: 'cut',
  3158. target,
  3159. purpose
  3160. });
  3161. },
  3162. logEventStopped: (_name, target, purpose) => {
  3163. sequence.push({
  3164. outcome: 'stopped',
  3165. target,
  3166. purpose
  3167. });
  3168. },
  3169. logNoParent: (_name, target, purpose) => {
  3170. sequence.push({
  3171. outcome: 'no-parent',
  3172. target,
  3173. purpose
  3174. });
  3175. },
  3176. logEventNoHandlers: (_name, target) => {
  3177. sequence.push({
  3178. outcome: 'no-handlers-left',
  3179. target
  3180. });
  3181. },
  3182. logEventResponse: (_name, target, purpose) => {
  3183. sequence.push({
  3184. outcome: 'response',
  3185. purpose,
  3186. target
  3187. });
  3188. },
  3189. write: () => {
  3190. const finishTime = new Date().getTime();
  3191. if (contains$2([
  3192. 'mousemove',
  3193. 'mouseover',
  3194. 'mouseout',
  3195. systemInit()
  3196. ], eventName)) {
  3197. return;
  3198. }
  3199. console.log(eventName, {
  3200. event: eventName,
  3201. time: finishTime - startTime,
  3202. target: initialTarget.dom,
  3203. sequence: map$2(sequence, s => {
  3204. if (!contains$2([
  3205. 'cut',
  3206. 'stopped',
  3207. 'response'
  3208. ], s.outcome)) {
  3209. return s.outcome;
  3210. } else {
  3211. return '{' + s.purpose + '} ' + s.outcome + ' at (' + element(s.target) + ')';
  3212. }
  3213. })
  3214. });
  3215. }
  3216. };
  3217. };
  3218. const processEvent = (eventName, initialTarget, f) => {
  3219. const status = get$g(eventConfig.get(), eventName).orThunk(() => {
  3220. const patterns = keys(eventConfig.get());
  3221. return findMap(patterns, p => eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none());
  3222. }).getOr(EventConfiguration.NORMAL);
  3223. switch (status) {
  3224. case EventConfiguration.NORMAL:
  3225. return f(noLogger());
  3226. case EventConfiguration.LOGGING: {
  3227. const logger = makeEventLogger(eventName, initialTarget);
  3228. const output = f(logger);
  3229. logger.write();
  3230. return output;
  3231. }
  3232. case EventConfiguration.STOP:
  3233. return true;
  3234. }
  3235. };
  3236. const path = [
  3237. 'alloy/data/Fields',
  3238. 'alloy/debugging/Debugging'
  3239. ];
  3240. const getTrace = () => {
  3241. const err = new Error();
  3242. if (err.stack !== undefined) {
  3243. const lines = err.stack.split('\n');
  3244. return find$5(lines, line => line.indexOf('alloy') > 0 && !exists(path, p => line.indexOf(p) > -1)).getOr(unknown);
  3245. } else {
  3246. return unknown;
  3247. }
  3248. };
  3249. const ignoreEvent = {
  3250. logEventCut: noop,
  3251. logEventStopped: noop,
  3252. logNoParent: noop,
  3253. logEventNoHandlers: noop,
  3254. logEventResponse: noop,
  3255. write: noop
  3256. };
  3257. const monitorEvent = (eventName, initialTarget, f) => processEvent(eventName, initialTarget, f);
  3258. const noLogger = constant$1(ignoreEvent);
  3259. const menuFields = constant$1([
  3260. required$1('menu'),
  3261. required$1('selectedMenu')
  3262. ]);
  3263. const itemFields = constant$1([
  3264. required$1('item'),
  3265. required$1('selectedItem')
  3266. ]);
  3267. constant$1(objOf(itemFields().concat(menuFields())));
  3268. const itemSchema$3 = constant$1(objOf(itemFields()));
  3269. const _initSize = requiredObjOf('initSize', [
  3270. required$1('numColumns'),
  3271. required$1('numRows')
  3272. ]);
  3273. const itemMarkers = () => requiredOf('markers', itemSchema$3());
  3274. const tieredMenuMarkers = () => requiredObjOf('markers', [required$1('backgroundMenu')].concat(menuFields()).concat(itemFields()));
  3275. const markers$1 = required => requiredObjOf('markers', map$2(required, required$1));
  3276. const onPresenceHandler = (label, fieldName, presence) => {
  3277. getTrace();
  3278. return field$1(fieldName, fieldName, presence, valueOf(f => Result.value((...args) => {
  3279. return f.apply(undefined, args);
  3280. })));
  3281. };
  3282. const onHandler = fieldName => onPresenceHandler('onHandler', fieldName, defaulted$1(noop));
  3283. const onKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, defaulted$1(Optional.none));
  3284. const onStrictHandler = fieldName => onPresenceHandler('onHandler', fieldName, required$2());
  3285. const onStrictKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, required$2());
  3286. const output$1 = (name, value) => customField(name, constant$1(value));
  3287. const snapshot = name => customField(name, identity);
  3288. const initSize = constant$1(_initSize);
  3289. const nu$6 = (x, y, bubble, direction, placement, boundsRestriction, labelPrefix, alwaysFit = false) => ({
  3290. x,
  3291. y,
  3292. bubble,
  3293. direction,
  3294. placement,
  3295. restriction: boundsRestriction,
  3296. label: `${ labelPrefix }-${ placement }`,
  3297. alwaysFit
  3298. });
  3299. const adt$a = Adt.generate([
  3300. { southeast: [] },
  3301. { southwest: [] },
  3302. { northeast: [] },
  3303. { northwest: [] },
  3304. { south: [] },
  3305. { north: [] },
  3306. { east: [] },
  3307. { west: [] }
  3308. ]);
  3309. const cata$2 = (subject, southeast, southwest, northeast, northwest, south, north, east, west) => subject.fold(southeast, southwest, northeast, northwest, south, north, east, west);
  3310. const cataVertical = (subject, south, middle, north) => subject.fold(south, south, north, north, south, north, middle, middle);
  3311. const cataHorizontal = (subject, east, middle, west) => subject.fold(east, west, east, west, middle, middle, east, west);
  3312. const southeast$3 = adt$a.southeast;
  3313. const southwest$3 = adt$a.southwest;
  3314. const northeast$3 = adt$a.northeast;
  3315. const northwest$3 = adt$a.northwest;
  3316. const south$3 = adt$a.south;
  3317. const north$3 = adt$a.north;
  3318. const east$3 = adt$a.east;
  3319. const west$3 = adt$a.west;
  3320. const cycleBy = (value, delta, min, max) => {
  3321. const r = value + delta;
  3322. if (r > max) {
  3323. return min;
  3324. } else if (r < min) {
  3325. return max;
  3326. } else {
  3327. return r;
  3328. }
  3329. };
  3330. const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
  3331. const getRestriction = (anchor, restriction) => {
  3332. switch (restriction) {
  3333. case 1:
  3334. return anchor.x;
  3335. case 0:
  3336. return anchor.x + anchor.width;
  3337. case 2:
  3338. return anchor.y;
  3339. case 3:
  3340. return anchor.y + anchor.height;
  3341. }
  3342. };
  3343. const boundsRestriction = (anchor, restrictions) => mapToObject([
  3344. 'left',
  3345. 'right',
  3346. 'top',
  3347. 'bottom'
  3348. ], dir => get$g(restrictions, dir).map(restriction => getRestriction(anchor, restriction)));
  3349. const adjustBounds = (bounds$1, restriction, bubbleOffset) => {
  3350. const applyRestriction = (dir, current) => restriction[dir].map(pos => {
  3351. const isVerticalAxis = dir === 'top' || dir === 'bottom';
  3352. const offset = isVerticalAxis ? bubbleOffset.top : bubbleOffset.left;
  3353. const comparator = dir === 'left' || dir === 'top' ? Math.max : Math.min;
  3354. const newPos = comparator(pos, current) + offset;
  3355. return isVerticalAxis ? clamp(newPos, bounds$1.y, bounds$1.bottom) : clamp(newPos, bounds$1.x, bounds$1.right);
  3356. }).getOr(current);
  3357. const adjustedLeft = applyRestriction('left', bounds$1.x);
  3358. const adjustedTop = applyRestriction('top', bounds$1.y);
  3359. const adjustedRight = applyRestriction('right', bounds$1.right);
  3360. const adjustedBottom = applyRestriction('bottom', bounds$1.bottom);
  3361. return bounds(adjustedLeft, adjustedTop, adjustedRight - adjustedLeft, adjustedBottom - adjustedTop);
  3362. };
  3363. const labelPrefix$2 = 'layout';
  3364. const eastX$1 = anchor => anchor.x;
  3365. const middleX$1 = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
  3366. const westX$1 = (anchor, element) => anchor.x + anchor.width - element.width;
  3367. const northY$2 = (anchor, element) => anchor.y - element.height;
  3368. const southY$2 = anchor => anchor.y + anchor.height;
  3369. const centreY$1 = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
  3370. const eastEdgeX$1 = anchor => anchor.x + anchor.width;
  3371. const westEdgeX$1 = (anchor, element) => anchor.x - element.width;
  3372. const southeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), southY$2(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
  3373. left: 1,
  3374. top: 3
  3375. }), labelPrefix$2);
  3376. const southwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), southY$2(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
  3377. right: 0,
  3378. top: 3
  3379. }), labelPrefix$2);
  3380. const northeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), northY$2(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
  3381. left: 1,
  3382. bottom: 2
  3383. }), labelPrefix$2);
  3384. const northwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), northY$2(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
  3385. right: 0,
  3386. bottom: 2
  3387. }), labelPrefix$2);
  3388. const north$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), northY$2(anchor, element), bubbles.north(), north$3(), 'north', boundsRestriction(anchor, { bottom: 2 }), labelPrefix$2);
  3389. const south$2 = (anchor, element, bubbles) => nu$6(middleX$1(anchor, element), southY$2(anchor), bubbles.south(), south$3(), 'south', boundsRestriction(anchor, { top: 3 }), labelPrefix$2);
  3390. const east$2 = (anchor, element, bubbles) => nu$6(eastEdgeX$1(anchor), centreY$1(anchor, element), bubbles.east(), east$3(), 'east', boundsRestriction(anchor, { left: 0 }), labelPrefix$2);
  3391. const west$2 = (anchor, element, bubbles) => nu$6(westEdgeX$1(anchor, element), centreY$1(anchor, element), bubbles.west(), west$3(), 'west', boundsRestriction(anchor, { right: 1 }), labelPrefix$2);
  3392. const all$1 = () => [
  3393. southeast$2,
  3394. southwest$2,
  3395. northeast$2,
  3396. northwest$2,
  3397. south$2,
  3398. north$2,
  3399. east$2,
  3400. west$2
  3401. ];
  3402. const allRtl$1 = () => [
  3403. southwest$2,
  3404. southeast$2,
  3405. northwest$2,
  3406. northeast$2,
  3407. south$2,
  3408. north$2,
  3409. east$2,
  3410. west$2
  3411. ];
  3412. const aboveOrBelow = () => [
  3413. northeast$2,
  3414. northwest$2,
  3415. southeast$2,
  3416. southwest$2,
  3417. north$2,
  3418. south$2
  3419. ];
  3420. const aboveOrBelowRtl = () => [
  3421. northwest$2,
  3422. northeast$2,
  3423. southwest$2,
  3424. southeast$2,
  3425. north$2,
  3426. south$2
  3427. ];
  3428. const belowOrAbove = () => [
  3429. southeast$2,
  3430. southwest$2,
  3431. northeast$2,
  3432. northwest$2,
  3433. south$2,
  3434. north$2
  3435. ];
  3436. const belowOrAboveRtl = () => [
  3437. southwest$2,
  3438. southeast$2,
  3439. northwest$2,
  3440. northeast$2,
  3441. south$2,
  3442. north$2
  3443. ];
  3444. const chooseChannels = (channels, message) => message.universal ? channels : filter$2(channels, ch => contains$2(message.channels, ch));
  3445. const events$h = receiveConfig => derive$2([run$1(receive(), (component, message) => {
  3446. const channelMap = receiveConfig.channels;
  3447. const channels = keys(channelMap);
  3448. const receivingData = message;
  3449. const targetChannels = chooseChannels(channels, receivingData);
  3450. each$1(targetChannels, ch => {
  3451. const channelInfo = channelMap[ch];
  3452. const channelSchema = channelInfo.schema;
  3453. const data = asRawOrDie$1('channel[' + ch + '] data\nReceiver: ' + element(component.element), channelSchema, receivingData.data);
  3454. channelInfo.onReceive(component, data);
  3455. });
  3456. })]);
  3457. var ActiveReceiving = /*#__PURE__*/Object.freeze({
  3458. __proto__: null,
  3459. events: events$h
  3460. });
  3461. var ReceivingSchema = [requiredOf('channels', setOf(Result.value, objOfOnly([
  3462. onStrictHandler('onReceive'),
  3463. defaulted('schema', anyValue())
  3464. ])))];
  3465. const executeEvent = (bConfig, bState, executor) => runOnExecute$1(component => {
  3466. executor(component, bConfig, bState);
  3467. });
  3468. const loadEvent = (bConfig, bState, f) => runOnInit((component, _simulatedEvent) => {
  3469. f(component, bConfig, bState);
  3470. });
  3471. const create$5 = (schema, name, active, apis, extra, state) => {
  3472. const configSchema = objOfOnly(schema);
  3473. const schemaSchema = optionObjOf(name, [optionObjOfOnly('config', schema)]);
  3474. return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
  3475. };
  3476. const createModes$1 = (modes, name, active, apis, extra, state) => {
  3477. const configSchema = modes;
  3478. const schemaSchema = optionObjOf(name, [optionOf('config', modes)]);
  3479. return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
  3480. };
  3481. const wrapApi = (bName, apiFunction, apiName) => {
  3482. const f = (component, ...rest) => {
  3483. const args = [component].concat(rest);
  3484. return component.config({ name: constant$1(bName) }).fold(() => {
  3485. throw new Error('We could not find any behaviour configuration for: ' + bName + '. Using API: ' + apiName);
  3486. }, info => {
  3487. const rest = Array.prototype.slice.call(args, 1);
  3488. return apiFunction.apply(undefined, [
  3489. component,
  3490. info.config,
  3491. info.state
  3492. ].concat(rest));
  3493. });
  3494. };
  3495. return markAsBehaviourApi(f, apiName, apiFunction);
  3496. };
  3497. const revokeBehaviour = name => ({
  3498. key: name,
  3499. value: undefined
  3500. });
  3501. const doCreate = (configSchema, schemaSchema, name, active, apis, extra, state) => {
  3502. const getConfig = info => hasNonNullableKey(info, name) ? info[name]() : Optional.none();
  3503. const wrappedApis = map$1(apis, (apiF, apiName) => wrapApi(name, apiF, apiName));
  3504. const wrappedExtra = map$1(extra, (extraF, extraName) => markAsExtraApi(extraF, extraName));
  3505. const me = {
  3506. ...wrappedExtra,
  3507. ...wrappedApis,
  3508. revoke: curry(revokeBehaviour, name),
  3509. config: spec => {
  3510. const prepared = asRawOrDie$1(name + '-config', configSchema, spec);
  3511. return {
  3512. key: name,
  3513. value: {
  3514. config: prepared,
  3515. me,
  3516. configAsRaw: cached(() => asRawOrDie$1(name + '-config', configSchema, spec)),
  3517. initialConfig: spec,
  3518. state
  3519. }
  3520. };
  3521. },
  3522. schema: constant$1(schemaSchema),
  3523. exhibit: (info, base) => {
  3524. return lift2(getConfig(info), get$g(active, 'exhibit'), (behaviourInfo, exhibitor) => {
  3525. return exhibitor(base, behaviourInfo.config, behaviourInfo.state);
  3526. }).getOrThunk(() => nu$7({}));
  3527. },
  3528. name: constant$1(name),
  3529. handlers: info => {
  3530. return getConfig(info).map(behaviourInfo => {
  3531. const getEvents = get$g(active, 'events').getOr(() => ({}));
  3532. return getEvents(behaviourInfo.config, behaviourInfo.state);
  3533. }).getOr({});
  3534. }
  3535. };
  3536. return me;
  3537. };
  3538. const derive$1 = capabilities => wrapAll(capabilities);
  3539. const simpleSchema = objOfOnly([
  3540. required$1('fields'),
  3541. required$1('name'),
  3542. defaulted('active', {}),
  3543. defaulted('apis', {}),
  3544. defaulted('state', NoState),
  3545. defaulted('extra', {})
  3546. ]);
  3547. const create$4 = data => {
  3548. const value = asRawOrDie$1('Creating behaviour: ' + data.name, simpleSchema, data);
  3549. return create$5(value.fields, value.name, value.active, value.apis, value.extra, value.state);
  3550. };
  3551. const modeSchema = objOfOnly([
  3552. required$1('branchKey'),
  3553. required$1('branches'),
  3554. required$1('name'),
  3555. defaulted('active', {}),
  3556. defaulted('apis', {}),
  3557. defaulted('state', NoState),
  3558. defaulted('extra', {})
  3559. ]);
  3560. const createModes = data => {
  3561. const value = asRawOrDie$1('Creating behaviour: ' + data.name, modeSchema, data);
  3562. return createModes$1(choose$1(value.branchKey, value.branches), value.name, value.active, value.apis, value.extra, value.state);
  3563. };
  3564. const revoke = constant$1(undefined);
  3565. const Receiving = create$4({
  3566. fields: ReceivingSchema,
  3567. name: 'receiving',
  3568. active: ActiveReceiving
  3569. });
  3570. const exhibit$6 = (base, posConfig) => nu$7({
  3571. classes: [],
  3572. styles: posConfig.useFixed() ? {} : { position: 'relative' }
  3573. });
  3574. var ActivePosition = /*#__PURE__*/Object.freeze({
  3575. __proto__: null,
  3576. exhibit: exhibit$6
  3577. });
  3578. const focus$3 = (element, preventScroll = false) => element.dom.focus({ preventScroll });
  3579. const blur$1 = element => element.dom.blur();
  3580. const hasFocus = element => {
  3581. const root = getRootNode(element).dom;
  3582. return element.dom === root.activeElement;
  3583. };
  3584. const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
  3585. const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
  3586. const preserve$1 = (f, container) => {
  3587. const dos = getRootNode(container);
  3588. const refocus = active$1(dos).bind(focused => {
  3589. const hasFocus = elem => eq(focused, elem);
  3590. return hasFocus(container) ? Optional.some(container) : descendant$1(container, hasFocus);
  3591. });
  3592. const result = f(container);
  3593. refocus.each(oldFocus => {
  3594. active$1(dos).filter(newFocus => eq(newFocus, oldFocus)).fold(() => {
  3595. focus$3(oldFocus);
  3596. }, noop);
  3597. });
  3598. return result;
  3599. };
  3600. const NuPositionCss = (position, left, top, right, bottom) => {
  3601. const toPx = num => num + 'px';
  3602. return {
  3603. position,
  3604. left: left.map(toPx),
  3605. top: top.map(toPx),
  3606. right: right.map(toPx),
  3607. bottom: bottom.map(toPx)
  3608. };
  3609. };
  3610. const toOptions = position => ({
  3611. ...position,
  3612. position: Optional.some(position.position)
  3613. });
  3614. const applyPositionCss = (element, position) => {
  3615. setOptions(element, toOptions(position));
  3616. };
  3617. const adt$9 = Adt.generate([
  3618. { none: [] },
  3619. {
  3620. relative: [
  3621. 'x',
  3622. 'y',
  3623. 'width',
  3624. 'height'
  3625. ]
  3626. },
  3627. {
  3628. fixed: [
  3629. 'x',
  3630. 'y',
  3631. 'width',
  3632. 'height'
  3633. ]
  3634. }
  3635. ]);
  3636. const positionWithDirection = (posName, decision, x, y, width, height) => {
  3637. const decisionRect = decision.rect;
  3638. const decisionX = decisionRect.x - x;
  3639. const decisionY = decisionRect.y - y;
  3640. const decisionWidth = decisionRect.width;
  3641. const decisionHeight = decisionRect.height;
  3642. const decisionRight = width - (decisionX + decisionWidth);
  3643. const decisionBottom = height - (decisionY + decisionHeight);
  3644. const left = Optional.some(decisionX);
  3645. const top = Optional.some(decisionY);
  3646. const right = Optional.some(decisionRight);
  3647. const bottom = Optional.some(decisionBottom);
  3648. const none = Optional.none();
  3649. return cata$2(decision.direction, () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, none, none, right, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, left, none, none, bottom), () => NuPositionCss(posName, left, top, none, none), () => NuPositionCss(posName, none, top, right, none));
  3650. };
  3651. const reposition = (origin, decision) => origin.fold(() => {
  3652. const decisionRect = decision.rect;
  3653. return NuPositionCss('absolute', Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
  3654. }, (x, y, width, height) => {
  3655. return positionWithDirection('absolute', decision, x, y, width, height);
  3656. }, (x, y, width, height) => {
  3657. return positionWithDirection('fixed', decision, x, y, width, height);
  3658. });
  3659. const toBox = (origin, element) => {
  3660. const rel = curry(find$2, element);
  3661. const position = origin.fold(rel, rel, () => {
  3662. const scroll = get$b();
  3663. return find$2(element).translate(-scroll.left, -scroll.top);
  3664. });
  3665. const width = getOuter$1(element);
  3666. const height = getOuter$2(element);
  3667. return bounds(position.left, position.top, width, height);
  3668. };
  3669. const viewport = (origin, optBounds) => optBounds.fold(() => origin.fold(win, win, bounds), bounds$1 => origin.fold(constant$1(bounds$1), constant$1(bounds$1), () => {
  3670. const pos = translate$2(origin, bounds$1.x, bounds$1.y);
  3671. return bounds(pos.left, pos.top, bounds$1.width, bounds$1.height);
  3672. }));
  3673. const translate$2 = (origin, x, y) => {
  3674. const pos = SugarPosition(x, y);
  3675. const removeScroll = () => {
  3676. const outerScroll = get$b();
  3677. return pos.translate(-outerScroll.left, -outerScroll.top);
  3678. };
  3679. return origin.fold(constant$1(pos), constant$1(pos), removeScroll);
  3680. };
  3681. const cata$1 = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
  3682. adt$9.none;
  3683. const relative$1 = adt$9.relative;
  3684. const fixed$1 = adt$9.fixed;
  3685. const anchor = (anchorBox, origin) => ({
  3686. anchorBox,
  3687. origin
  3688. });
  3689. const box = (anchorBox, origin) => anchor(anchorBox, origin);
  3690. const placementAttribute = 'data-alloy-placement';
  3691. const setPlacement$1 = (element, placement) => {
  3692. set$9(element, placementAttribute, placement);
  3693. };
  3694. const getPlacement = element => getOpt(element, placementAttribute);
  3695. const reset$2 = element => remove$7(element, placementAttribute);
  3696. const adt$8 = Adt.generate([
  3697. { fit: ['reposition'] },
  3698. {
  3699. nofit: [
  3700. 'reposition',
  3701. 'visibleW',
  3702. 'visibleH',
  3703. 'isVisible'
  3704. ]
  3705. }
  3706. ]);
  3707. const determinePosition = (box, bounds) => {
  3708. const {
  3709. x: boundsX,
  3710. y: boundsY,
  3711. right: boundsRight,
  3712. bottom: boundsBottom
  3713. } = bounds;
  3714. const {x, y, right, bottom, width, height} = box;
  3715. const xInBounds = x >= boundsX && x <= boundsRight;
  3716. const yInBounds = y >= boundsY && y <= boundsBottom;
  3717. const originInBounds = xInBounds && yInBounds;
  3718. const rightInBounds = right <= boundsRight && right >= boundsX;
  3719. const bottomInBounds = bottom <= boundsBottom && bottom >= boundsY;
  3720. const sizeInBounds = rightInBounds && bottomInBounds;
  3721. const visibleW = Math.min(width, x >= boundsX ? boundsRight - x : right - boundsX);
  3722. const visibleH = Math.min(height, y >= boundsY ? boundsBottom - y : bottom - boundsY);
  3723. return {
  3724. originInBounds,
  3725. sizeInBounds,
  3726. visibleW,
  3727. visibleH
  3728. };
  3729. };
  3730. const calcReposition = (box, bounds$1) => {
  3731. const {
  3732. x: boundsX,
  3733. y: boundsY,
  3734. right: boundsRight,
  3735. bottom: boundsBottom
  3736. } = bounds$1;
  3737. const {x, y, width, height} = box;
  3738. const maxX = Math.max(boundsX, boundsRight - width);
  3739. const maxY = Math.max(boundsY, boundsBottom - height);
  3740. const restrictedX = clamp(x, boundsX, maxX);
  3741. const restrictedY = clamp(y, boundsY, maxY);
  3742. const restrictedWidth = Math.min(restrictedX + width, boundsRight) - restrictedX;
  3743. const restrictedHeight = Math.min(restrictedY + height, boundsBottom) - restrictedY;
  3744. return bounds(restrictedX, restrictedY, restrictedWidth, restrictedHeight);
  3745. };
  3746. const calcMaxSizes = (direction, box, bounds) => {
  3747. const upAvailable = constant$1(box.bottom - bounds.y);
  3748. const downAvailable = constant$1(bounds.bottom - box.y);
  3749. const maxHeight = cataVertical(direction, downAvailable, downAvailable, upAvailable);
  3750. const westAvailable = constant$1(box.right - bounds.x);
  3751. const eastAvailable = constant$1(bounds.right - box.x);
  3752. const maxWidth = cataHorizontal(direction, eastAvailable, eastAvailable, westAvailable);
  3753. return {
  3754. maxWidth,
  3755. maxHeight
  3756. };
  3757. };
  3758. const attempt = (candidate, width, height, bounds$1) => {
  3759. const bubble = candidate.bubble;
  3760. const bubbleOffset = bubble.offset;
  3761. const adjustedBounds = adjustBounds(bounds$1, candidate.restriction, bubbleOffset);
  3762. const newX = candidate.x + bubbleOffset.left;
  3763. const newY = candidate.y + bubbleOffset.top;
  3764. const box = bounds(newX, newY, width, height);
  3765. const {originInBounds, sizeInBounds, visibleW, visibleH} = determinePosition(box, adjustedBounds);
  3766. const fits = originInBounds && sizeInBounds;
  3767. const fittedBox = fits ? box : calcReposition(box, adjustedBounds);
  3768. const isPartlyVisible = fittedBox.width > 0 && fittedBox.height > 0;
  3769. const {maxWidth, maxHeight} = calcMaxSizes(candidate.direction, fittedBox, bounds$1);
  3770. const reposition = {
  3771. rect: fittedBox,
  3772. maxHeight,
  3773. maxWidth,
  3774. direction: candidate.direction,
  3775. placement: candidate.placement,
  3776. classes: {
  3777. on: bubble.classesOn,
  3778. off: bubble.classesOff
  3779. },
  3780. layout: candidate.label,
  3781. testY: newY
  3782. };
  3783. return fits || candidate.alwaysFit ? adt$8.fit(reposition) : adt$8.nofit(reposition, visibleW, visibleH, isPartlyVisible);
  3784. };
  3785. const attempts = (element, candidates, anchorBox, elementBox, bubbles, bounds) => {
  3786. const panelWidth = elementBox.width;
  3787. const panelHeight = elementBox.height;
  3788. const attemptBestFit = (layout, reposition, visibleW, visibleH, isVisible) => {
  3789. const next = layout(anchorBox, elementBox, bubbles, element, bounds);
  3790. const attemptLayout = attempt(next, panelWidth, panelHeight, bounds);
  3791. return attemptLayout.fold(constant$1(attemptLayout), (newReposition, newVisibleW, newVisibleH, newIsVisible) => {
  3792. const improved = isVisible === newIsVisible ? newVisibleH > visibleH || newVisibleW > visibleW : !isVisible && newIsVisible;
  3793. return improved ? attemptLayout : adt$8.nofit(reposition, visibleW, visibleH, isVisible);
  3794. });
  3795. };
  3796. const abc = foldl(candidates, (b, a) => {
  3797. const bestNext = curry(attemptBestFit, a);
  3798. return b.fold(constant$1(b), bestNext);
  3799. }, adt$8.nofit({
  3800. rect: anchorBox,
  3801. maxHeight: elementBox.height,
  3802. maxWidth: elementBox.width,
  3803. direction: southeast$3(),
  3804. placement: 'southeast',
  3805. classes: {
  3806. on: [],
  3807. off: []
  3808. },
  3809. layout: 'none',
  3810. testY: anchorBox.y
  3811. }, -1, -1, false));
  3812. return abc.fold(identity, identity);
  3813. };
  3814. const singleton = doRevoke => {
  3815. const subject = Cell(Optional.none());
  3816. const revoke = () => subject.get().each(doRevoke);
  3817. const clear = () => {
  3818. revoke();
  3819. subject.set(Optional.none());
  3820. };
  3821. const isSet = () => subject.get().isSome();
  3822. const get = () => subject.get();
  3823. const set = s => {
  3824. revoke();
  3825. subject.set(Optional.some(s));
  3826. };
  3827. return {
  3828. clear,
  3829. isSet,
  3830. get,
  3831. set
  3832. };
  3833. };
  3834. const destroyable = () => singleton(s => s.destroy());
  3835. const unbindable = () => singleton(s => s.unbind());
  3836. const value$2 = () => {
  3837. const subject = singleton(noop);
  3838. const on = f => subject.get().each(f);
  3839. return {
  3840. ...subject,
  3841. on
  3842. };
  3843. };
  3844. const filter = always;
  3845. const bind = (element, event, handler) => bind$2(element, event, filter, handler);
  3846. const capture = (element, event, handler) => capture$1(element, event, filter, handler);
  3847. const fromRawEvent = fromRawEvent$1;
  3848. const properties = [
  3849. 'top',
  3850. 'bottom',
  3851. 'right',
  3852. 'left'
  3853. ];
  3854. const timerAttr = 'data-alloy-transition-timer';
  3855. const isTransitioning$1 = (element, transition) => hasAll(element, transition.classes);
  3856. const shouldApplyTransitionCss = (transition, decision, lastPlacement) => {
  3857. return lastPlacement.exists(placer => {
  3858. const mode = transition.mode;
  3859. return mode === 'all' ? true : placer[mode] !== decision[mode];
  3860. });
  3861. };
  3862. const hasChanges = (position, intermediate) => {
  3863. const round = value => parseFloat(value).toFixed(3);
  3864. return find$4(intermediate, (value, key) => {
  3865. const newValue = position[key].map(round);
  3866. const val = value.map(round);
  3867. return !equals(newValue, val);
  3868. }).isSome();
  3869. };
  3870. const getTransitionDuration = element => {
  3871. const get = name => {
  3872. const style = get$e(element, name);
  3873. const times = style.split(/\s*,\s*/);
  3874. return filter$2(times, isNotEmpty);
  3875. };
  3876. const parse = value => {
  3877. if (isString(value) && /^[\d.]+/.test(value)) {
  3878. const num = parseFloat(value);
  3879. return endsWith(value, 'ms') ? num : num * 1000;
  3880. } else {
  3881. return 0;
  3882. }
  3883. };
  3884. const delay = get('transition-delay');
  3885. const duration = get('transition-duration');
  3886. return foldl(duration, (acc, dur, i) => {
  3887. const time = parse(delay[i]) + parse(dur);
  3888. return Math.max(acc, time);
  3889. }, 0);
  3890. };
  3891. const setupTransitionListeners = (element, transition) => {
  3892. const transitionEnd = unbindable();
  3893. const transitionCancel = unbindable();
  3894. let timer;
  3895. const isSourceTransition = e => {
  3896. var _a;
  3897. const pseudoElement = (_a = e.raw.pseudoElement) !== null && _a !== void 0 ? _a : '';
  3898. return eq(e.target, element) && isEmpty(pseudoElement) && contains$2(properties, e.raw.propertyName);
  3899. };
  3900. const transitionDone = e => {
  3901. if (isNullable(e) || isSourceTransition(e)) {
  3902. transitionEnd.clear();
  3903. transitionCancel.clear();
  3904. const type = e === null || e === void 0 ? void 0 : e.raw.type;
  3905. if (isNullable(type) || type === transitionend()) {
  3906. clearTimeout(timer);
  3907. remove$7(element, timerAttr);
  3908. remove$1(element, transition.classes);
  3909. }
  3910. }
  3911. };
  3912. const transitionStart = bind(element, transitionstart(), e => {
  3913. if (isSourceTransition(e)) {
  3914. transitionStart.unbind();
  3915. transitionEnd.set(bind(element, transitionend(), transitionDone));
  3916. transitionCancel.set(bind(element, transitioncancel(), transitionDone));
  3917. }
  3918. });
  3919. const duration = getTransitionDuration(element);
  3920. requestAnimationFrame(() => {
  3921. timer = setTimeout(transitionDone, duration + 17);
  3922. set$9(element, timerAttr, timer);
  3923. });
  3924. };
  3925. const startTransitioning = (element, transition) => {
  3926. add$1(element, transition.classes);
  3927. getOpt(element, timerAttr).each(timerId => {
  3928. clearTimeout(parseInt(timerId, 10));
  3929. remove$7(element, timerAttr);
  3930. });
  3931. setupTransitionListeners(element, transition);
  3932. };
  3933. const applyTransitionCss = (element, origin, position, transition, decision, lastPlacement) => {
  3934. const shouldTransition = shouldApplyTransitionCss(transition, decision, lastPlacement);
  3935. if (shouldTransition || isTransitioning$1(element, transition)) {
  3936. set$8(element, 'position', position.position);
  3937. const rect = toBox(origin, element);
  3938. const intermediatePosition = reposition(origin, {
  3939. ...decision,
  3940. rect
  3941. });
  3942. const intermediateCssOptions = mapToObject(properties, prop => intermediatePosition[prop]);
  3943. if (hasChanges(position, intermediateCssOptions)) {
  3944. setOptions(element, intermediateCssOptions);
  3945. if (shouldTransition) {
  3946. startTransitioning(element, transition);
  3947. }
  3948. reflow(element);
  3949. }
  3950. } else {
  3951. remove$1(element, transition.classes);
  3952. }
  3953. };
  3954. const elementSize = p => ({
  3955. width: getOuter$1(p),
  3956. height: getOuter$2(p)
  3957. });
  3958. const layout = (anchorBox, element, bubbles, options) => {
  3959. remove$6(element, 'max-height');
  3960. remove$6(element, 'max-width');
  3961. const elementBox = elementSize(element);
  3962. return attempts(element, options.preference, anchorBox, elementBox, bubbles, options.bounds);
  3963. };
  3964. const setClasses = (element, decision) => {
  3965. const classInfo = decision.classes;
  3966. remove$1(element, classInfo.off);
  3967. add$1(element, classInfo.on);
  3968. };
  3969. const setHeight = (element, decision, options) => {
  3970. const maxHeightFunction = options.maxHeightFunction;
  3971. maxHeightFunction(element, decision.maxHeight);
  3972. };
  3973. const setWidth = (element, decision, options) => {
  3974. const maxWidthFunction = options.maxWidthFunction;
  3975. maxWidthFunction(element, decision.maxWidth);
  3976. };
  3977. const position$2 = (element, decision, options) => {
  3978. const positionCss = reposition(options.origin, decision);
  3979. options.transition.each(transition => {
  3980. applyTransitionCss(element, options.origin, positionCss, transition, decision, options.lastPlacement);
  3981. });
  3982. applyPositionCss(element, positionCss);
  3983. };
  3984. const setPlacement = (element, decision) => {
  3985. setPlacement$1(element, decision.placement);
  3986. };
  3987. const setMaxHeight = (element, maxHeight) => {
  3988. setMax$1(element, Math.floor(maxHeight));
  3989. };
  3990. const anchored = constant$1((element, available) => {
  3991. setMaxHeight(element, available);
  3992. setAll(element, {
  3993. 'overflow-x': 'hidden',
  3994. 'overflow-y': 'auto'
  3995. });
  3996. });
  3997. const expandable$1 = constant$1((element, available) => {
  3998. setMaxHeight(element, available);
  3999. });
  4000. const defaultOr = (options, key, dephault) => options[key] === undefined ? dephault : options[key];
  4001. const simple = (anchor, element, bubble, layouts, lastPlacement, optBounds, overrideOptions, transition) => {
  4002. const maxHeightFunction = defaultOr(overrideOptions, 'maxHeightFunction', anchored());
  4003. const maxWidthFunction = defaultOr(overrideOptions, 'maxWidthFunction', noop);
  4004. const anchorBox = anchor.anchorBox;
  4005. const origin = anchor.origin;
  4006. const options = {
  4007. bounds: viewport(origin, optBounds),
  4008. origin,
  4009. preference: layouts,
  4010. maxHeightFunction,
  4011. maxWidthFunction,
  4012. lastPlacement,
  4013. transition
  4014. };
  4015. return go(anchorBox, element, bubble, options);
  4016. };
  4017. const go = (anchorBox, element, bubble, options) => {
  4018. const decision = layout(anchorBox, element, bubble, options);
  4019. position$2(element, decision, options);
  4020. setPlacement(element, decision);
  4021. setClasses(element, decision);
  4022. setHeight(element, decision, options);
  4023. setWidth(element, decision, options);
  4024. return {
  4025. layout: decision.layout,
  4026. placement: decision.placement
  4027. };
  4028. };
  4029. const allAlignments = [
  4030. 'valignCentre',
  4031. 'alignLeft',
  4032. 'alignRight',
  4033. 'alignCentre',
  4034. 'top',
  4035. 'bottom',
  4036. 'left',
  4037. 'right',
  4038. 'inset'
  4039. ];
  4040. const nu$5 = (xOffset, yOffset, classes, insetModifier = 1) => {
  4041. const insetXOffset = xOffset * insetModifier;
  4042. const insetYOffset = yOffset * insetModifier;
  4043. const getClasses = prop => get$g(classes, prop).getOr([]);
  4044. const make = (xDelta, yDelta, alignmentsOn) => {
  4045. const alignmentsOff = difference(allAlignments, alignmentsOn);
  4046. return {
  4047. offset: SugarPosition(xDelta, yDelta),
  4048. classesOn: bind$3(alignmentsOn, getClasses),
  4049. classesOff: bind$3(alignmentsOff, getClasses)
  4050. };
  4051. };
  4052. return {
  4053. southeast: () => make(-xOffset, yOffset, [
  4054. 'top',
  4055. 'alignLeft'
  4056. ]),
  4057. southwest: () => make(xOffset, yOffset, [
  4058. 'top',
  4059. 'alignRight'
  4060. ]),
  4061. south: () => make(-xOffset / 2, yOffset, [
  4062. 'top',
  4063. 'alignCentre'
  4064. ]),
  4065. northeast: () => make(-xOffset, -yOffset, [
  4066. 'bottom',
  4067. 'alignLeft'
  4068. ]),
  4069. northwest: () => make(xOffset, -yOffset, [
  4070. 'bottom',
  4071. 'alignRight'
  4072. ]),
  4073. north: () => make(-xOffset / 2, -yOffset, [
  4074. 'bottom',
  4075. 'alignCentre'
  4076. ]),
  4077. east: () => make(xOffset, -yOffset / 2, [
  4078. 'valignCentre',
  4079. 'left'
  4080. ]),
  4081. west: () => make(-xOffset, -yOffset / 2, [
  4082. 'valignCentre',
  4083. 'right'
  4084. ]),
  4085. insetNortheast: () => make(insetXOffset, insetYOffset, [
  4086. 'top',
  4087. 'alignLeft',
  4088. 'inset'
  4089. ]),
  4090. insetNorthwest: () => make(-insetXOffset, insetYOffset, [
  4091. 'top',
  4092. 'alignRight',
  4093. 'inset'
  4094. ]),
  4095. insetNorth: () => make(-insetXOffset / 2, insetYOffset, [
  4096. 'top',
  4097. 'alignCentre',
  4098. 'inset'
  4099. ]),
  4100. insetSoutheast: () => make(insetXOffset, -insetYOffset, [
  4101. 'bottom',
  4102. 'alignLeft',
  4103. 'inset'
  4104. ]),
  4105. insetSouthwest: () => make(-insetXOffset, -insetYOffset, [
  4106. 'bottom',
  4107. 'alignRight',
  4108. 'inset'
  4109. ]),
  4110. insetSouth: () => make(-insetXOffset / 2, -insetYOffset, [
  4111. 'bottom',
  4112. 'alignCentre',
  4113. 'inset'
  4114. ]),
  4115. insetEast: () => make(-insetXOffset, -insetYOffset / 2, [
  4116. 'valignCentre',
  4117. 'right',
  4118. 'inset'
  4119. ]),
  4120. insetWest: () => make(insetXOffset, -insetYOffset / 2, [
  4121. 'valignCentre',
  4122. 'left',
  4123. 'inset'
  4124. ])
  4125. };
  4126. };
  4127. const fallback = () => nu$5(0, 0, {});
  4128. const nu$4 = identity;
  4129. const onDirection = (isLtr, isRtl) => element => getDirection(element) === 'rtl' ? isRtl : isLtr;
  4130. const getDirection = element => get$e(element, 'direction') === 'rtl' ? 'rtl' : 'ltr';
  4131. var AttributeValue;
  4132. (function (AttributeValue) {
  4133. AttributeValue['TopToBottom'] = 'toptobottom';
  4134. AttributeValue['BottomToTop'] = 'bottomtotop';
  4135. }(AttributeValue || (AttributeValue = {})));
  4136. const Attribute = 'data-alloy-vertical-dir';
  4137. const isBottomToTopDir = el => closest$2(el, current => isElement$1(current) && get$f(current, 'data-alloy-vertical-dir') === AttributeValue.BottomToTop);
  4138. const schema$y = () => optionObjOf('layouts', [
  4139. required$1('onLtr'),
  4140. required$1('onRtl'),
  4141. option$3('onBottomLtr'),
  4142. option$3('onBottomRtl')
  4143. ]);
  4144. const get$5 = (elem, info, defaultLtr, defaultRtl, defaultBottomLtr, defaultBottomRtl, dirElement) => {
  4145. const isBottomToTop = dirElement.map(isBottomToTopDir).getOr(false);
  4146. const customLtr = info.layouts.map(ls => ls.onLtr(elem));
  4147. const customRtl = info.layouts.map(ls => ls.onRtl(elem));
  4148. const ltr = isBottomToTop ? info.layouts.bind(ls => ls.onBottomLtr.map(f => f(elem))).or(customLtr).getOr(defaultBottomLtr) : customLtr.getOr(defaultLtr);
  4149. const rtl = isBottomToTop ? info.layouts.bind(ls => ls.onBottomRtl.map(f => f(elem))).or(customRtl).getOr(defaultBottomRtl) : customRtl.getOr(defaultRtl);
  4150. const f = onDirection(ltr, rtl);
  4151. return f(elem);
  4152. };
  4153. const placement$4 = (component, anchorInfo, origin) => {
  4154. const hotspot = anchorInfo.hotspot;
  4155. const anchorBox = toBox(origin, hotspot.element);
  4156. const layouts = get$5(component.element, anchorInfo, belowOrAbove(), belowOrAboveRtl(), aboveOrBelow(), aboveOrBelowRtl(), Optional.some(anchorInfo.hotspot.element));
  4157. return Optional.some(nu$4({
  4158. anchorBox,
  4159. bubble: anchorInfo.bubble.getOr(fallback()),
  4160. overrides: anchorInfo.overrides,
  4161. layouts
  4162. }));
  4163. };
  4164. var HotspotAnchor = [
  4165. required$1('hotspot'),
  4166. option$3('bubble'),
  4167. defaulted('overrides', {}),
  4168. schema$y(),
  4169. output$1('placement', placement$4)
  4170. ];
  4171. const placement$3 = (component, anchorInfo, origin) => {
  4172. const pos = translate$2(origin, anchorInfo.x, anchorInfo.y);
  4173. const anchorBox = bounds(pos.left, pos.top, anchorInfo.width, anchorInfo.height);
  4174. const layouts = get$5(component.element, anchorInfo, all$1(), allRtl$1(), all$1(), allRtl$1(), Optional.none());
  4175. return Optional.some(nu$4({
  4176. anchorBox,
  4177. bubble: anchorInfo.bubble,
  4178. overrides: anchorInfo.overrides,
  4179. layouts
  4180. }));
  4181. };
  4182. var MakeshiftAnchor = [
  4183. required$1('x'),
  4184. required$1('y'),
  4185. defaulted('height', 0),
  4186. defaulted('width', 0),
  4187. defaulted('bubble', fallback()),
  4188. defaulted('overrides', {}),
  4189. schema$y(),
  4190. output$1('placement', placement$3)
  4191. ];
  4192. const adt$7 = Adt.generate([
  4193. { screen: ['point'] },
  4194. {
  4195. absolute: [
  4196. 'point',
  4197. 'scrollLeft',
  4198. 'scrollTop'
  4199. ]
  4200. }
  4201. ]);
  4202. const toFixed = pos => pos.fold(identity, (point, scrollLeft, scrollTop) => point.translate(-scrollLeft, -scrollTop));
  4203. const toAbsolute = pos => pos.fold(identity, identity);
  4204. const sum = points => foldl(points, (b, a) => b.translate(a.left, a.top), SugarPosition(0, 0));
  4205. const sumAsFixed = positions => {
  4206. const points = map$2(positions, toFixed);
  4207. return sum(points);
  4208. };
  4209. const sumAsAbsolute = positions => {
  4210. const points = map$2(positions, toAbsolute);
  4211. return sum(points);
  4212. };
  4213. const screen = adt$7.screen;
  4214. const absolute$1 = adt$7.absolute;
  4215. const getOffset = (component, origin, anchorInfo) => {
  4216. const win = defaultView(anchorInfo.root).dom;
  4217. const hasSameOwner = frame => {
  4218. const frameOwner = owner$4(frame);
  4219. const compOwner = owner$4(component.element);
  4220. return eq(frameOwner, compOwner);
  4221. };
  4222. return Optional.from(win.frameElement).map(SugarElement.fromDom).filter(hasSameOwner).map(absolute$3);
  4223. };
  4224. const getRootPoint = (component, origin, anchorInfo) => {
  4225. const doc = owner$4(component.element);
  4226. const outerScroll = get$b(doc);
  4227. const offset = getOffset(component, origin, anchorInfo).getOr(outerScroll);
  4228. return absolute$1(offset, outerScroll.left, outerScroll.top);
  4229. };
  4230. const getBox = (left, top, width, height) => {
  4231. const point = screen(SugarPosition(left, top));
  4232. return Optional.some(pointed(point, width, height));
  4233. };
  4234. const calcNewAnchor = (optBox, rootPoint, anchorInfo, origin, elem) => optBox.map(box => {
  4235. const points = [
  4236. rootPoint,
  4237. box.point
  4238. ];
  4239. const topLeft = cata$1(origin, () => sumAsAbsolute(points), () => sumAsAbsolute(points), () => sumAsFixed(points));
  4240. const anchorBox = rect(topLeft.left, topLeft.top, box.width, box.height);
  4241. const layoutsLtr = anchorInfo.showAbove ? aboveOrBelow() : belowOrAbove();
  4242. const layoutsRtl = anchorInfo.showAbove ? aboveOrBelowRtl() : belowOrAboveRtl();
  4243. const layouts = get$5(elem, anchorInfo, layoutsLtr, layoutsRtl, layoutsLtr, layoutsRtl, Optional.none());
  4244. return nu$4({
  4245. anchorBox,
  4246. bubble: anchorInfo.bubble.getOr(fallback()),
  4247. overrides: anchorInfo.overrides,
  4248. layouts
  4249. });
  4250. });
  4251. const placement$2 = (component, anchorInfo, origin) => {
  4252. const rootPoint = getRootPoint(component, origin, anchorInfo);
  4253. return anchorInfo.node.filter(inBody).bind(target => {
  4254. const rect = target.dom.getBoundingClientRect();
  4255. const nodeBox = getBox(rect.left, rect.top, rect.width, rect.height);
  4256. const elem = anchorInfo.node.getOr(component.element);
  4257. return calcNewAnchor(nodeBox, rootPoint, anchorInfo, origin, elem);
  4258. });
  4259. };
  4260. var NodeAnchor = [
  4261. required$1('node'),
  4262. required$1('root'),
  4263. option$3('bubble'),
  4264. schema$y(),
  4265. defaulted('overrides', {}),
  4266. defaulted('showAbove', false),
  4267. output$1('placement', placement$2)
  4268. ];
  4269. const zeroWidth = '\uFEFF';
  4270. const nbsp = '\xA0';
  4271. const create$3 = (start, soffset, finish, foffset) => ({
  4272. start,
  4273. soffset,
  4274. finish,
  4275. foffset
  4276. });
  4277. const SimRange = { create: create$3 };
  4278. const adt$6 = Adt.generate([
  4279. { before: ['element'] },
  4280. {
  4281. on: [
  4282. 'element',
  4283. 'offset'
  4284. ]
  4285. },
  4286. { after: ['element'] }
  4287. ]);
  4288. const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
  4289. const getStart$1 = situ => situ.fold(identity, identity, identity);
  4290. const before = adt$6.before;
  4291. const on$1 = adt$6.on;
  4292. const after$1 = adt$6.after;
  4293. const Situ = {
  4294. before,
  4295. on: on$1,
  4296. after: after$1,
  4297. cata,
  4298. getStart: getStart$1
  4299. };
  4300. const adt$5 = Adt.generate([
  4301. { domRange: ['rng'] },
  4302. {
  4303. relative: [
  4304. 'startSitu',
  4305. 'finishSitu'
  4306. ]
  4307. },
  4308. {
  4309. exact: [
  4310. 'start',
  4311. 'soffset',
  4312. 'finish',
  4313. 'foffset'
  4314. ]
  4315. }
  4316. ]);
  4317. const exactFromRange = simRange => adt$5.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
  4318. const getStart = selection => selection.match({
  4319. domRange: rng => SugarElement.fromDom(rng.startContainer),
  4320. relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
  4321. exact: (start, _soffset, _finish, _foffset) => start
  4322. });
  4323. const domRange = adt$5.domRange;
  4324. const relative = adt$5.relative;
  4325. const exact = adt$5.exact;
  4326. const getWin = selection => {
  4327. const start = getStart(selection);
  4328. return defaultView(start);
  4329. };
  4330. const range$1 = SimRange.create;
  4331. const SimSelection = {
  4332. domRange,
  4333. relative,
  4334. exact,
  4335. exactFromRange,
  4336. getWin,
  4337. range: range$1
  4338. };
  4339. const setStart = (rng, situ) => {
  4340. situ.fold(e => {
  4341. rng.setStartBefore(e.dom);
  4342. }, (e, o) => {
  4343. rng.setStart(e.dom, o);
  4344. }, e => {
  4345. rng.setStartAfter(e.dom);
  4346. });
  4347. };
  4348. const setFinish = (rng, situ) => {
  4349. situ.fold(e => {
  4350. rng.setEndBefore(e.dom);
  4351. }, (e, o) => {
  4352. rng.setEnd(e.dom, o);
  4353. }, e => {
  4354. rng.setEndAfter(e.dom);
  4355. });
  4356. };
  4357. const relativeToNative = (win, startSitu, finishSitu) => {
  4358. const range = win.document.createRange();
  4359. setStart(range, startSitu);
  4360. setFinish(range, finishSitu);
  4361. return range;
  4362. };
  4363. const exactToNative = (win, start, soffset, finish, foffset) => {
  4364. const rng = win.document.createRange();
  4365. rng.setStart(start.dom, soffset);
  4366. rng.setEnd(finish.dom, foffset);
  4367. return rng;
  4368. };
  4369. const toRect = rect => ({
  4370. left: rect.left,
  4371. top: rect.top,
  4372. right: rect.right,
  4373. bottom: rect.bottom,
  4374. width: rect.width,
  4375. height: rect.height
  4376. });
  4377. const getFirstRect$1 = rng => {
  4378. const rects = rng.getClientRects();
  4379. const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
  4380. return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
  4381. };
  4382. const getBounds$2 = rng => {
  4383. const rect = rng.getBoundingClientRect();
  4384. return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
  4385. };
  4386. const adt$4 = Adt.generate([
  4387. {
  4388. ltr: [
  4389. 'start',
  4390. 'soffset',
  4391. 'finish',
  4392. 'foffset'
  4393. ]
  4394. },
  4395. {
  4396. rtl: [
  4397. 'start',
  4398. 'soffset',
  4399. 'finish',
  4400. 'foffset'
  4401. ]
  4402. }
  4403. ]);
  4404. const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
  4405. const getRanges = (win, selection) => selection.match({
  4406. domRange: rng => {
  4407. return {
  4408. ltr: constant$1(rng),
  4409. rtl: Optional.none
  4410. };
  4411. },
  4412. relative: (startSitu, finishSitu) => {
  4413. return {
  4414. ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
  4415. rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
  4416. };
  4417. },
  4418. exact: (start, soffset, finish, foffset) => {
  4419. return {
  4420. ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
  4421. rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
  4422. };
  4423. }
  4424. });
  4425. const doDiagnose = (win, ranges) => {
  4426. const rng = ranges.ltr();
  4427. if (rng.collapsed) {
  4428. const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
  4429. return reversed.map(rev => adt$4.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$4.ltr, rng));
  4430. } else {
  4431. return fromRange(win, adt$4.ltr, rng);
  4432. }
  4433. };
  4434. const diagnose = (win, selection) => {
  4435. const ranges = getRanges(win, selection);
  4436. return doDiagnose(win, ranges);
  4437. };
  4438. const asLtrRange = (win, selection) => {
  4439. const diagnosis = diagnose(win, selection);
  4440. return diagnosis.match({
  4441. ltr: (start, soffset, finish, foffset) => {
  4442. const rng = win.document.createRange();
  4443. rng.setStart(start.dom, soffset);
  4444. rng.setEnd(finish.dom, foffset);
  4445. return rng;
  4446. },
  4447. rtl: (start, soffset, finish, foffset) => {
  4448. const rng = win.document.createRange();
  4449. rng.setStart(finish.dom, foffset);
  4450. rng.setEnd(start.dom, soffset);
  4451. return rng;
  4452. }
  4453. });
  4454. };
  4455. adt$4.ltr;
  4456. adt$4.rtl;
  4457. const ancestors = (scope, predicate, isRoot) => filter$2(parents(scope, isRoot), predicate);
  4458. const descendants = (scope, selector) => all$3(selector, scope);
  4459. const makeRange = (start, soffset, finish, foffset) => {
  4460. const doc = owner$4(start);
  4461. const rng = doc.dom.createRange();
  4462. rng.setStart(start.dom, soffset);
  4463. rng.setEnd(finish.dom, foffset);
  4464. return rng;
  4465. };
  4466. const after = (start, soffset, finish, foffset) => {
  4467. const r = makeRange(start, soffset, finish, foffset);
  4468. const same = eq(start, finish) && soffset === foffset;
  4469. return r.collapsed && !same;
  4470. };
  4471. const getNativeSelection = win => Optional.from(win.getSelection());
  4472. const readRange = selection => {
  4473. if (selection.rangeCount > 0) {
  4474. const firstRng = selection.getRangeAt(0);
  4475. const lastRng = selection.getRangeAt(selection.rangeCount - 1);
  4476. return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
  4477. } else {
  4478. return Optional.none();
  4479. }
  4480. };
  4481. const doGetExact = selection => {
  4482. if (selection.anchorNode === null || selection.focusNode === null) {
  4483. return readRange(selection);
  4484. } else {
  4485. const anchor = SugarElement.fromDom(selection.anchorNode);
  4486. const focus = SugarElement.fromDom(selection.focusNode);
  4487. return after(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection);
  4488. }
  4489. };
  4490. const getExact = win => getNativeSelection(win).filter(sel => sel.rangeCount > 0).bind(doGetExact);
  4491. const getFirstRect = (win, selection) => {
  4492. const rng = asLtrRange(win, selection);
  4493. return getFirstRect$1(rng);
  4494. };
  4495. const getBounds$1 = (win, selection) => {
  4496. const rng = asLtrRange(win, selection);
  4497. return getBounds$2(rng);
  4498. };
  4499. const NodeValue = (is, name) => {
  4500. const get = element => {
  4501. if (!is(element)) {
  4502. throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
  4503. }
  4504. return getOption(element).getOr('');
  4505. };
  4506. const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
  4507. const set = (element, value) => {
  4508. if (!is(element)) {
  4509. throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
  4510. }
  4511. element.dom.nodeValue = value;
  4512. };
  4513. return {
  4514. get,
  4515. getOption,
  4516. set
  4517. };
  4518. };
  4519. const api = NodeValue(isText, 'text');
  4520. const get$4 = element => api.get(element);
  4521. const point = (element, offset) => ({
  4522. element,
  4523. offset
  4524. });
  4525. const descendOnce$1 = (element, offset) => {
  4526. const children$1 = children(element);
  4527. if (children$1.length === 0) {
  4528. return point(element, offset);
  4529. } else if (offset < children$1.length) {
  4530. return point(children$1[offset], 0);
  4531. } else {
  4532. const last = children$1[children$1.length - 1];
  4533. const len = isText(last) ? get$4(last).length : children(last).length;
  4534. return point(last, len);
  4535. }
  4536. };
  4537. const descendOnce = (element, offset) => isText(element) ? point(element, offset) : descendOnce$1(element, offset);
  4538. const isSimRange = detail => detail.foffset !== undefined;
  4539. const getAnchorSelection = (win, anchorInfo) => {
  4540. const getSelection = anchorInfo.getSelection.getOrThunk(() => () => getExact(win));
  4541. return getSelection().map(sel => {
  4542. if (isSimRange(sel)) {
  4543. const modStart = descendOnce(sel.start, sel.soffset);
  4544. const modFinish = descendOnce(sel.finish, sel.foffset);
  4545. return SimSelection.range(modStart.element, modStart.offset, modFinish.element, modFinish.offset);
  4546. } else {
  4547. return sel;
  4548. }
  4549. });
  4550. };
  4551. const placement$1 = (component, anchorInfo, origin) => {
  4552. const win = defaultView(anchorInfo.root).dom;
  4553. const rootPoint = getRootPoint(component, origin, anchorInfo);
  4554. const selectionBox = getAnchorSelection(win, anchorInfo).bind(sel => {
  4555. if (isSimRange(sel)) {
  4556. const optRect = getBounds$1(win, SimSelection.exactFromRange(sel)).orThunk(() => {
  4557. const zeroWidth$1 = SugarElement.fromText(zeroWidth);
  4558. before$1(sel.start, zeroWidth$1);
  4559. const rect = getFirstRect(win, SimSelection.exact(zeroWidth$1, 0, zeroWidth$1, 1));
  4560. remove$5(zeroWidth$1);
  4561. return rect;
  4562. });
  4563. return optRect.bind(rawRect => {
  4564. return getBox(rawRect.left, rawRect.top, rawRect.width, rawRect.height);
  4565. });
  4566. } else {
  4567. const selectionRect = map$1(sel, cell => cell.dom.getBoundingClientRect());
  4568. const bounds = {
  4569. left: Math.min(selectionRect.firstCell.left, selectionRect.lastCell.left),
  4570. right: Math.max(selectionRect.firstCell.right, selectionRect.lastCell.right),
  4571. top: Math.min(selectionRect.firstCell.top, selectionRect.lastCell.top),
  4572. bottom: Math.max(selectionRect.firstCell.bottom, selectionRect.lastCell.bottom)
  4573. };
  4574. return getBox(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
  4575. }
  4576. });
  4577. const targetElement = getAnchorSelection(win, anchorInfo).bind(sel => {
  4578. if (isSimRange(sel)) {
  4579. return isElement$1(sel.start) ? Optional.some(sel.start) : parentElement(sel.start);
  4580. } else {
  4581. return Optional.some(sel.firstCell);
  4582. }
  4583. });
  4584. const elem = targetElement.getOr(component.element);
  4585. return calcNewAnchor(selectionBox, rootPoint, anchorInfo, origin, elem);
  4586. };
  4587. var SelectionAnchor = [
  4588. option$3('getSelection'),
  4589. required$1('root'),
  4590. option$3('bubble'),
  4591. schema$y(),
  4592. defaulted('overrides', {}),
  4593. defaulted('showAbove', false),
  4594. output$1('placement', placement$1)
  4595. ];
  4596. const labelPrefix$1 = 'link-layout';
  4597. const eastX = anchor => anchor.x + anchor.width;
  4598. const westX = (anchor, element) => anchor.x - element.width;
  4599. const northY$1 = (anchor, element) => anchor.y - element.height + anchor.height;
  4600. const southY$1 = anchor => anchor.y;
  4601. const southeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), southY$1(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
  4602. left: 0,
  4603. top: 2
  4604. }), labelPrefix$1);
  4605. const southwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), southY$1(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
  4606. right: 1,
  4607. top: 2
  4608. }), labelPrefix$1);
  4609. const northeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), northY$1(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
  4610. left: 0,
  4611. bottom: 3
  4612. }), labelPrefix$1);
  4613. const northwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), northY$1(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
  4614. right: 1,
  4615. bottom: 3
  4616. }), labelPrefix$1);
  4617. const all = () => [
  4618. southeast$1,
  4619. southwest$1,
  4620. northeast$1,
  4621. northwest$1
  4622. ];
  4623. const allRtl = () => [
  4624. southwest$1,
  4625. southeast$1,
  4626. northwest$1,
  4627. northeast$1
  4628. ];
  4629. const placement = (component, submenuInfo, origin) => {
  4630. const anchorBox = toBox(origin, submenuInfo.item.element);
  4631. const layouts = get$5(component.element, submenuInfo, all(), allRtl(), all(), allRtl(), Optional.none());
  4632. return Optional.some(nu$4({
  4633. anchorBox,
  4634. bubble: fallback(),
  4635. overrides: submenuInfo.overrides,
  4636. layouts
  4637. }));
  4638. };
  4639. var SubmenuAnchor = [
  4640. required$1('item'),
  4641. schema$y(),
  4642. defaulted('overrides', {}),
  4643. output$1('placement', placement)
  4644. ];
  4645. var AnchorSchema = choose$1('type', {
  4646. selection: SelectionAnchor,
  4647. node: NodeAnchor,
  4648. hotspot: HotspotAnchor,
  4649. submenu: SubmenuAnchor,
  4650. makeshift: MakeshiftAnchor
  4651. });
  4652. const TransitionSchema = [
  4653. requiredArrayOf('classes', string),
  4654. defaultedStringEnum('mode', 'all', [
  4655. 'all',
  4656. 'layout',
  4657. 'placement'
  4658. ])
  4659. ];
  4660. const PositionSchema = [
  4661. defaulted('useFixed', never),
  4662. option$3('getBounds')
  4663. ];
  4664. const PlacementSchema = [
  4665. requiredOf('anchor', AnchorSchema),
  4666. optionObjOf('transition', TransitionSchema)
  4667. ];
  4668. const getFixedOrigin = () => {
  4669. const html = document.documentElement;
  4670. return fixed$1(0, 0, html.clientWidth, html.clientHeight);
  4671. };
  4672. const getRelativeOrigin = component => {
  4673. const position = absolute$3(component.element);
  4674. const bounds = component.element.dom.getBoundingClientRect();
  4675. return relative$1(position.left, position.top, bounds.width, bounds.height);
  4676. };
  4677. const place = (origin, anchoring, optBounds, placee, lastPlace, transition) => {
  4678. const anchor = box(anchoring.anchorBox, origin);
  4679. return simple(anchor, placee.element, anchoring.bubble, anchoring.layouts, lastPlace, optBounds, anchoring.overrides, transition);
  4680. };
  4681. const position$1 = (component, posConfig, posState, placee, placementSpec) => {
  4682. const optWithinBounds = Optional.none();
  4683. positionWithinBounds(component, posConfig, posState, placee, placementSpec, optWithinBounds);
  4684. };
  4685. const positionWithinBounds = (component, posConfig, posState, placee, placementSpec, optWithinBounds) => {
  4686. const placeeDetail = asRawOrDie$1('placement.info', objOf(PlacementSchema), placementSpec);
  4687. const anchorage = placeeDetail.anchor;
  4688. const element = placee.element;
  4689. const placeeState = posState.get(placee.uid);
  4690. preserve$1(() => {
  4691. set$8(element, 'position', 'fixed');
  4692. const oldVisibility = getRaw(element, 'visibility');
  4693. set$8(element, 'visibility', 'hidden');
  4694. const origin = posConfig.useFixed() ? getFixedOrigin() : getRelativeOrigin(component);
  4695. anchorage.placement(component, anchorage, origin).each(anchoring => {
  4696. const optBounds = optWithinBounds.orThunk(() => posConfig.getBounds.map(apply$1));
  4697. const newState = place(origin, anchoring, optBounds, placee, placeeState, placeeDetail.transition);
  4698. posState.set(placee.uid, newState);
  4699. });
  4700. oldVisibility.fold(() => {
  4701. remove$6(element, 'visibility');
  4702. }, vis => {
  4703. set$8(element, 'visibility', vis);
  4704. });
  4705. if (getRaw(element, 'left').isNone() && getRaw(element, 'top').isNone() && getRaw(element, 'right').isNone() && getRaw(element, 'bottom').isNone() && is$1(getRaw(element, 'position'), 'fixed')) {
  4706. remove$6(element, 'position');
  4707. }
  4708. }, element);
  4709. };
  4710. const getMode = (component, pConfig, _pState) => pConfig.useFixed() ? 'fixed' : 'absolute';
  4711. const reset$1 = (component, pConfig, posState, placee) => {
  4712. const element = placee.element;
  4713. each$1([
  4714. 'position',
  4715. 'left',
  4716. 'right',
  4717. 'top',
  4718. 'bottom'
  4719. ], prop => remove$6(element, prop));
  4720. reset$2(element);
  4721. posState.clear(placee.uid);
  4722. };
  4723. var PositionApis = /*#__PURE__*/Object.freeze({
  4724. __proto__: null,
  4725. position: position$1,
  4726. positionWithinBounds: positionWithinBounds,
  4727. getMode: getMode,
  4728. reset: reset$1
  4729. });
  4730. const init$g = () => {
  4731. let state = {};
  4732. const set = (id, data) => {
  4733. state[id] = data;
  4734. };
  4735. const get = id => get$g(state, id);
  4736. const clear = id => {
  4737. if (isNonNullable(id)) {
  4738. delete state[id];
  4739. } else {
  4740. state = {};
  4741. }
  4742. };
  4743. return nu$8({
  4744. readState: () => state,
  4745. clear,
  4746. set,
  4747. get
  4748. });
  4749. };
  4750. var PositioningState = /*#__PURE__*/Object.freeze({
  4751. __proto__: null,
  4752. init: init$g
  4753. });
  4754. const Positioning = create$4({
  4755. fields: PositionSchema,
  4756. name: 'positioning',
  4757. active: ActivePosition,
  4758. apis: PositionApis,
  4759. state: PositioningState
  4760. });
  4761. const isConnected = comp => comp.getSystem().isConnected();
  4762. const fireDetaching = component => {
  4763. emit(component, detachedFromDom());
  4764. const children = component.components();
  4765. each$1(children, fireDetaching);
  4766. };
  4767. const fireAttaching = component => {
  4768. const children = component.components();
  4769. each$1(children, fireAttaching);
  4770. emit(component, attachedToDom());
  4771. };
  4772. const virtualAttach = (parent, child) => {
  4773. parent.getSystem().addToWorld(child);
  4774. if (inBody(parent.element)) {
  4775. fireAttaching(child);
  4776. }
  4777. };
  4778. const virtualDetach = comp => {
  4779. fireDetaching(comp);
  4780. comp.getSystem().removeFromWorld(comp);
  4781. };
  4782. const attach$1 = (parent, child) => {
  4783. append$2(parent.element, child.element);
  4784. };
  4785. const detachChildren$1 = component => {
  4786. each$1(component.components(), childComp => remove$5(childComp.element));
  4787. empty(component.element);
  4788. component.syncComponents();
  4789. };
  4790. const replaceChildren = (component, newSpecs, buildNewChildren) => {
  4791. const subs = component.components();
  4792. detachChildren$1(component);
  4793. const newChildren = buildNewChildren(newSpecs);
  4794. const deleted = difference(subs, newChildren);
  4795. each$1(deleted, comp => {
  4796. fireDetaching(comp);
  4797. component.getSystem().removeFromWorld(comp);
  4798. });
  4799. each$1(newChildren, childComp => {
  4800. if (!isConnected(childComp)) {
  4801. component.getSystem().addToWorld(childComp);
  4802. attach$1(component, childComp);
  4803. if (inBody(component.element)) {
  4804. fireAttaching(childComp);
  4805. }
  4806. } else {
  4807. attach$1(component, childComp);
  4808. }
  4809. });
  4810. component.syncComponents();
  4811. };
  4812. const virtualReplaceChildren = (component, newSpecs, buildNewChildren) => {
  4813. const subs = component.components();
  4814. const existingComps = bind$3(newSpecs, spec => getPremade(spec).toArray());
  4815. each$1(subs, childComp => {
  4816. if (!contains$2(existingComps, childComp)) {
  4817. virtualDetach(childComp);
  4818. }
  4819. });
  4820. const newChildren = buildNewChildren(newSpecs);
  4821. const deleted = difference(subs, newChildren);
  4822. each$1(deleted, deletedComp => {
  4823. if (isConnected(deletedComp)) {
  4824. virtualDetach(deletedComp);
  4825. }
  4826. });
  4827. each$1(newChildren, childComp => {
  4828. if (!isConnected(childComp)) {
  4829. virtualAttach(component, childComp);
  4830. }
  4831. });
  4832. component.syncComponents();
  4833. };
  4834. const attach = (parent, child) => {
  4835. attachWith(parent, child, append$2);
  4836. };
  4837. const attachWith = (parent, child, insertion) => {
  4838. parent.getSystem().addToWorld(child);
  4839. insertion(parent.element, child.element);
  4840. if (inBody(parent.element)) {
  4841. fireAttaching(child);
  4842. }
  4843. parent.syncComponents();
  4844. };
  4845. const doDetach = component => {
  4846. fireDetaching(component);
  4847. remove$5(component.element);
  4848. component.getSystem().removeFromWorld(component);
  4849. };
  4850. const detach = component => {
  4851. const parent$1 = parent(component.element).bind(p => component.getSystem().getByDom(p).toOptional());
  4852. doDetach(component);
  4853. parent$1.each(p => {
  4854. p.syncComponents();
  4855. });
  4856. };
  4857. const detachChildren = component => {
  4858. const subs = component.components();
  4859. each$1(subs, doDetach);
  4860. empty(component.element);
  4861. component.syncComponents();
  4862. };
  4863. const attachSystem = (element, guiSystem) => {
  4864. attachSystemWith(element, guiSystem, append$2);
  4865. };
  4866. const attachSystemAfter = (element, guiSystem) => {
  4867. attachSystemWith(element, guiSystem, after$2);
  4868. };
  4869. const attachSystemWith = (element, guiSystem, inserter) => {
  4870. inserter(element, guiSystem.element);
  4871. const children$1 = children(guiSystem.element);
  4872. each$1(children$1, child => {
  4873. guiSystem.getByDom(child).each(fireAttaching);
  4874. });
  4875. };
  4876. const detachSystem = guiSystem => {
  4877. const children$1 = children(guiSystem.element);
  4878. each$1(children$1, child => {
  4879. guiSystem.getByDom(child).each(fireDetaching);
  4880. });
  4881. remove$5(guiSystem.element);
  4882. };
  4883. const rebuild = (sandbox, sConfig, sState, data) => {
  4884. sState.get().each(_data => {
  4885. detachChildren(sandbox);
  4886. });
  4887. const point = sConfig.getAttachPoint(sandbox);
  4888. attach(point, sandbox);
  4889. const built = sandbox.getSystem().build(data);
  4890. attach(sandbox, built);
  4891. sState.set(built);
  4892. return built;
  4893. };
  4894. const open$1 = (sandbox, sConfig, sState, data) => {
  4895. const newState = rebuild(sandbox, sConfig, sState, data);
  4896. sConfig.onOpen(sandbox, newState);
  4897. return newState;
  4898. };
  4899. const setContent = (sandbox, sConfig, sState, data) => sState.get().map(() => rebuild(sandbox, sConfig, sState, data));
  4900. const openWhileCloaked = (sandbox, sConfig, sState, data, transaction) => {
  4901. cloak(sandbox, sConfig);
  4902. open$1(sandbox, sConfig, sState, data);
  4903. transaction();
  4904. decloak(sandbox, sConfig);
  4905. };
  4906. const close$1 = (sandbox, sConfig, sState) => {
  4907. sState.get().each(data => {
  4908. detachChildren(sandbox);
  4909. detach(sandbox);
  4910. sConfig.onClose(sandbox, data);
  4911. sState.clear();
  4912. });
  4913. };
  4914. const isOpen$1 = (_sandbox, _sConfig, sState) => sState.isOpen();
  4915. const isPartOf = (sandbox, sConfig, sState, queryElem) => isOpen$1(sandbox, sConfig, sState) && sState.get().exists(data => sConfig.isPartOf(sandbox, data, queryElem));
  4916. const getState$2 = (_sandbox, _sConfig, sState) => sState.get();
  4917. const store = (sandbox, cssKey, attr, newValue) => {
  4918. getRaw(sandbox.element, cssKey).fold(() => {
  4919. remove$7(sandbox.element, attr);
  4920. }, v => {
  4921. set$9(sandbox.element, attr, v);
  4922. });
  4923. set$8(sandbox.element, cssKey, newValue);
  4924. };
  4925. const restore = (sandbox, cssKey, attr) => {
  4926. getOpt(sandbox.element, attr).fold(() => remove$6(sandbox.element, cssKey), oldValue => set$8(sandbox.element, cssKey, oldValue));
  4927. };
  4928. const cloak = (sandbox, sConfig, _sState) => {
  4929. const sink = sConfig.getAttachPoint(sandbox);
  4930. set$8(sandbox.element, 'position', Positioning.getMode(sink));
  4931. store(sandbox, 'visibility', sConfig.cloakVisibilityAttr, 'hidden');
  4932. };
  4933. const hasPosition = element => exists([
  4934. 'top',
  4935. 'left',
  4936. 'right',
  4937. 'bottom'
  4938. ], pos => getRaw(element, pos).isSome());
  4939. const decloak = (sandbox, sConfig, _sState) => {
  4940. if (!hasPosition(sandbox.element)) {
  4941. remove$6(sandbox.element, 'position');
  4942. }
  4943. restore(sandbox, 'visibility', sConfig.cloakVisibilityAttr);
  4944. };
  4945. var SandboxApis = /*#__PURE__*/Object.freeze({
  4946. __proto__: null,
  4947. cloak: cloak,
  4948. decloak: decloak,
  4949. open: open$1,
  4950. openWhileCloaked: openWhileCloaked,
  4951. close: close$1,
  4952. isOpen: isOpen$1,
  4953. isPartOf: isPartOf,
  4954. getState: getState$2,
  4955. setContent: setContent
  4956. });
  4957. const events$g = (sandboxConfig, sandboxState) => derive$2([run$1(sandboxClose(), (sandbox, _simulatedEvent) => {
  4958. close$1(sandbox, sandboxConfig, sandboxState);
  4959. })]);
  4960. var ActiveSandbox = /*#__PURE__*/Object.freeze({
  4961. __proto__: null,
  4962. events: events$g
  4963. });
  4964. var SandboxSchema = [
  4965. onHandler('onOpen'),
  4966. onHandler('onClose'),
  4967. required$1('isPartOf'),
  4968. required$1('getAttachPoint'),
  4969. defaulted('cloakVisibilityAttr', 'data-precloak-visibility')
  4970. ];
  4971. const init$f = () => {
  4972. const contents = value$2();
  4973. const readState = constant$1('not-implemented');
  4974. return nu$8({
  4975. readState,
  4976. isOpen: contents.isSet,
  4977. clear: contents.clear,
  4978. set: contents.set,
  4979. get: contents.get
  4980. });
  4981. };
  4982. var SandboxState = /*#__PURE__*/Object.freeze({
  4983. __proto__: null,
  4984. init: init$f
  4985. });
  4986. const Sandboxing = create$4({
  4987. fields: SandboxSchema,
  4988. name: 'sandboxing',
  4989. active: ActiveSandbox,
  4990. apis: SandboxApis,
  4991. state: SandboxState
  4992. });
  4993. const dismissPopups = constant$1('dismiss.popups');
  4994. const repositionPopups = constant$1('reposition.popups');
  4995. const mouseReleased = constant$1('mouse.released');
  4996. const schema$x = objOfOnly([
  4997. defaulted('isExtraPart', never),
  4998. optionObjOf('fireEventInstead', [defaulted('event', dismissRequested())])
  4999. ]);
  5000. const receivingChannel$1 = rawSpec => {
  5001. const detail = asRawOrDie$1('Dismissal', schema$x, rawSpec);
  5002. return {
  5003. [dismissPopups()]: {
  5004. schema: objOfOnly([required$1('target')]),
  5005. onReceive: (sandbox, data) => {
  5006. if (Sandboxing.isOpen(sandbox)) {
  5007. const isPart = Sandboxing.isPartOf(sandbox, data.target) || detail.isExtraPart(sandbox, data.target);
  5008. if (!isPart) {
  5009. detail.fireEventInstead.fold(() => Sandboxing.close(sandbox), fe => emit(sandbox, fe.event));
  5010. }
  5011. }
  5012. }
  5013. }
  5014. };
  5015. };
  5016. const schema$w = objOfOnly([
  5017. optionObjOf('fireEventInstead', [defaulted('event', repositionRequested())]),
  5018. requiredFunction('doReposition')
  5019. ]);
  5020. const receivingChannel = rawSpec => {
  5021. const detail = asRawOrDie$1('Reposition', schema$w, rawSpec);
  5022. return {
  5023. [repositionPopups()]: {
  5024. onReceive: sandbox => {
  5025. if (Sandboxing.isOpen(sandbox)) {
  5026. detail.fireEventInstead.fold(() => detail.doReposition(sandbox), fe => emit(sandbox, fe.event));
  5027. }
  5028. }
  5029. }
  5030. };
  5031. };
  5032. const onLoad$5 = (component, repConfig, repState) => {
  5033. repConfig.store.manager.onLoad(component, repConfig, repState);
  5034. };
  5035. const onUnload$2 = (component, repConfig, repState) => {
  5036. repConfig.store.manager.onUnload(component, repConfig, repState);
  5037. };
  5038. const setValue$3 = (component, repConfig, repState, data) => {
  5039. repConfig.store.manager.setValue(component, repConfig, repState, data);
  5040. };
  5041. const getValue$3 = (component, repConfig, repState) => repConfig.store.manager.getValue(component, repConfig, repState);
  5042. const getState$1 = (component, repConfig, repState) => repState;
  5043. var RepresentApis = /*#__PURE__*/Object.freeze({
  5044. __proto__: null,
  5045. onLoad: onLoad$5,
  5046. onUnload: onUnload$2,
  5047. setValue: setValue$3,
  5048. getValue: getValue$3,
  5049. getState: getState$1
  5050. });
  5051. const events$f = (repConfig, repState) => {
  5052. const es = repConfig.resetOnDom ? [
  5053. runOnAttached((comp, _se) => {
  5054. onLoad$5(comp, repConfig, repState);
  5055. }),
  5056. runOnDetached((comp, _se) => {
  5057. onUnload$2(comp, repConfig, repState);
  5058. })
  5059. ] : [loadEvent(repConfig, repState, onLoad$5)];
  5060. return derive$2(es);
  5061. };
  5062. var ActiveRepresenting = /*#__PURE__*/Object.freeze({
  5063. __proto__: null,
  5064. events: events$f
  5065. });
  5066. const memory$1 = () => {
  5067. const data = Cell(null);
  5068. const readState = () => ({
  5069. mode: 'memory',
  5070. value: data.get()
  5071. });
  5072. const isNotSet = () => data.get() === null;
  5073. const clear = () => {
  5074. data.set(null);
  5075. };
  5076. return nu$8({
  5077. set: data.set,
  5078. get: data.get,
  5079. isNotSet,
  5080. clear,
  5081. readState
  5082. });
  5083. };
  5084. const manual = () => {
  5085. const readState = noop;
  5086. return nu$8({ readState });
  5087. };
  5088. const dataset = () => {
  5089. const dataByValue = Cell({});
  5090. const dataByText = Cell({});
  5091. const readState = () => ({
  5092. mode: 'dataset',
  5093. dataByValue: dataByValue.get(),
  5094. dataByText: dataByText.get()
  5095. });
  5096. const clear = () => {
  5097. dataByValue.set({});
  5098. dataByText.set({});
  5099. };
  5100. const lookup = itemString => get$g(dataByValue.get(), itemString).orThunk(() => get$g(dataByText.get(), itemString));
  5101. const update = items => {
  5102. const currentDataByValue = dataByValue.get();
  5103. const currentDataByText = dataByText.get();
  5104. const newDataByValue = {};
  5105. const newDataByText = {};
  5106. each$1(items, item => {
  5107. newDataByValue[item.value] = item;
  5108. get$g(item, 'meta').each(meta => {
  5109. get$g(meta, 'text').each(text => {
  5110. newDataByText[text] = item;
  5111. });
  5112. });
  5113. });
  5114. dataByValue.set({
  5115. ...currentDataByValue,
  5116. ...newDataByValue
  5117. });
  5118. dataByText.set({
  5119. ...currentDataByText,
  5120. ...newDataByText
  5121. });
  5122. };
  5123. return nu$8({
  5124. readState,
  5125. lookup,
  5126. update,
  5127. clear
  5128. });
  5129. };
  5130. const init$e = spec => spec.store.manager.state(spec);
  5131. var RepresentState = /*#__PURE__*/Object.freeze({
  5132. __proto__: null,
  5133. memory: memory$1,
  5134. dataset: dataset,
  5135. manual: manual,
  5136. init: init$e
  5137. });
  5138. const setValue$2 = (component, repConfig, repState, data) => {
  5139. const store = repConfig.store;
  5140. repState.update([data]);
  5141. store.setValue(component, data);
  5142. repConfig.onSetValue(component, data);
  5143. };
  5144. const getValue$2 = (component, repConfig, repState) => {
  5145. const store = repConfig.store;
  5146. const key = store.getDataKey(component);
  5147. return repState.lookup(key).getOrThunk(() => store.getFallbackEntry(key));
  5148. };
  5149. const onLoad$4 = (component, repConfig, repState) => {
  5150. const store = repConfig.store;
  5151. store.initialValue.each(data => {
  5152. setValue$2(component, repConfig, repState, data);
  5153. });
  5154. };
  5155. const onUnload$1 = (component, repConfig, repState) => {
  5156. repState.clear();
  5157. };
  5158. var DatasetStore = [
  5159. option$3('initialValue'),
  5160. required$1('getFallbackEntry'),
  5161. required$1('getDataKey'),
  5162. required$1('setValue'),
  5163. output$1('manager', {
  5164. setValue: setValue$2,
  5165. getValue: getValue$2,
  5166. onLoad: onLoad$4,
  5167. onUnload: onUnload$1,
  5168. state: dataset
  5169. })
  5170. ];
  5171. const getValue$1 = (component, repConfig, _repState) => repConfig.store.getValue(component);
  5172. const setValue$1 = (component, repConfig, _repState, data) => {
  5173. repConfig.store.setValue(component, data);
  5174. repConfig.onSetValue(component, data);
  5175. };
  5176. const onLoad$3 = (component, repConfig, _repState) => {
  5177. repConfig.store.initialValue.each(data => {
  5178. repConfig.store.setValue(component, data);
  5179. });
  5180. };
  5181. var ManualStore = [
  5182. required$1('getValue'),
  5183. defaulted('setValue', noop),
  5184. option$3('initialValue'),
  5185. output$1('manager', {
  5186. setValue: setValue$1,
  5187. getValue: getValue$1,
  5188. onLoad: onLoad$3,
  5189. onUnload: noop,
  5190. state: NoState.init
  5191. })
  5192. ];
  5193. const setValue = (component, repConfig, repState, data) => {
  5194. repState.set(data);
  5195. repConfig.onSetValue(component, data);
  5196. };
  5197. const getValue = (component, repConfig, repState) => repState.get();
  5198. const onLoad$2 = (component, repConfig, repState) => {
  5199. repConfig.store.initialValue.each(initVal => {
  5200. if (repState.isNotSet()) {
  5201. repState.set(initVal);
  5202. }
  5203. });
  5204. };
  5205. const onUnload = (component, repConfig, repState) => {
  5206. repState.clear();
  5207. };
  5208. var MemoryStore = [
  5209. option$3('initialValue'),
  5210. output$1('manager', {
  5211. setValue,
  5212. getValue,
  5213. onLoad: onLoad$2,
  5214. onUnload,
  5215. state: memory$1
  5216. })
  5217. ];
  5218. var RepresentSchema = [
  5219. defaultedOf('store', { mode: 'memory' }, choose$1('mode', {
  5220. memory: MemoryStore,
  5221. manual: ManualStore,
  5222. dataset: DatasetStore
  5223. })),
  5224. onHandler('onSetValue'),
  5225. defaulted('resetOnDom', false)
  5226. ];
  5227. const Representing = create$4({
  5228. fields: RepresentSchema,
  5229. name: 'representing',
  5230. active: ActiveRepresenting,
  5231. apis: RepresentApis,
  5232. extra: {
  5233. setValueFrom: (component, source) => {
  5234. const value = Representing.getValue(source);
  5235. Representing.setValue(component, value);
  5236. }
  5237. },
  5238. state: RepresentState
  5239. });
  5240. const field = (name, forbidden) => defaultedObjOf(name, {}, map$2(forbidden, f => forbid(f.name(), 'Cannot configure ' + f.name() + ' for ' + name)).concat([customField('dump', identity)]));
  5241. const get$3 = data => data.dump;
  5242. const augment = (data, original) => ({
  5243. ...derive$1(original),
  5244. ...data.dump
  5245. });
  5246. const SketchBehaviours = {
  5247. field,
  5248. augment,
  5249. get: get$3
  5250. };
  5251. const _placeholder = 'placeholder';
  5252. const adt$3 = Adt.generate([
  5253. {
  5254. single: [
  5255. 'required',
  5256. 'valueThunk'
  5257. ]
  5258. },
  5259. {
  5260. multiple: [
  5261. 'required',
  5262. 'valueThunks'
  5263. ]
  5264. }
  5265. ]);
  5266. const isSubstituted = spec => has$2(spec, 'uiType');
  5267. const subPlaceholder = (owner, detail, compSpec, placeholders) => {
  5268. if (owner.exists(o => o !== compSpec.owner)) {
  5269. return adt$3.single(true, constant$1(compSpec));
  5270. }
  5271. return get$g(placeholders, compSpec.name).fold(() => {
  5272. throw new Error('Unknown placeholder component: ' + compSpec.name + '\nKnown: [' + keys(placeholders) + ']\nNamespace: ' + owner.getOr('none') + '\nSpec: ' + JSON.stringify(compSpec, null, 2));
  5273. }, newSpec => newSpec.replace());
  5274. };
  5275. const scan = (owner, detail, compSpec, placeholders) => {
  5276. if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
  5277. return subPlaceholder(owner, detail, compSpec, placeholders);
  5278. } else {
  5279. return adt$3.single(false, constant$1(compSpec));
  5280. }
  5281. };
  5282. const substitute = (owner, detail, compSpec, placeholders) => {
  5283. const base = scan(owner, detail, compSpec, placeholders);
  5284. return base.fold((req, valueThunk) => {
  5285. const value = isSubstituted(compSpec) ? valueThunk(detail, compSpec.config, compSpec.validated) : valueThunk(detail);
  5286. const childSpecs = get$g(value, 'components').getOr([]);
  5287. const substituted = bind$3(childSpecs, c => substitute(owner, detail, c, placeholders));
  5288. return [{
  5289. ...value,
  5290. components: substituted
  5291. }];
  5292. }, (req, valuesThunk) => {
  5293. if (isSubstituted(compSpec)) {
  5294. const values = valuesThunk(detail, compSpec.config, compSpec.validated);
  5295. const preprocessor = compSpec.validated.preprocess.getOr(identity);
  5296. return preprocessor(values);
  5297. } else {
  5298. return valuesThunk(detail);
  5299. }
  5300. });
  5301. };
  5302. const substituteAll = (owner, detail, components, placeholders) => bind$3(components, c => substitute(owner, detail, c, placeholders));
  5303. const oneReplace = (label, replacements) => {
  5304. let called = false;
  5305. const used = () => called;
  5306. const replace = () => {
  5307. if (called) {
  5308. throw new Error('Trying to use the same placeholder more than once: ' + label);
  5309. }
  5310. called = true;
  5311. return replacements;
  5312. };
  5313. const required = () => replacements.fold((req, _) => req, (req, _) => req);
  5314. return {
  5315. name: constant$1(label),
  5316. required,
  5317. used,
  5318. replace
  5319. };
  5320. };
  5321. const substitutePlaces = (owner, detail, components, placeholders) => {
  5322. const ps = map$1(placeholders, (ph, name) => oneReplace(name, ph));
  5323. const outcome = substituteAll(owner, detail, components, ps);
  5324. each(ps, p => {
  5325. if (p.used() === false && p.required()) {
  5326. throw new Error('Placeholder: ' + p.name() + ' was not found in components list\nNamespace: ' + owner.getOr('none') + '\nComponents: ' + JSON.stringify(detail.components, null, 2));
  5327. }
  5328. });
  5329. return outcome;
  5330. };
  5331. const single$2 = adt$3.single;
  5332. const multiple = adt$3.multiple;
  5333. const placeholder = constant$1(_placeholder);
  5334. const adt$2 = Adt.generate([
  5335. { required: ['data'] },
  5336. { external: ['data'] },
  5337. { optional: ['data'] },
  5338. { group: ['data'] }
  5339. ]);
  5340. const fFactory = defaulted('factory', { sketch: identity });
  5341. const fSchema = defaulted('schema', []);
  5342. const fName = required$1('name');
  5343. const fPname = field$1('pname', 'pname', defaultedThunk(typeSpec => '<alloy.' + generate$6(typeSpec.name) + '>'), anyValue());
  5344. const fGroupSchema = customField('schema', () => [option$3('preprocess')]);
  5345. const fDefaults = defaulted('defaults', constant$1({}));
  5346. const fOverrides = defaulted('overrides', constant$1({}));
  5347. const requiredSpec = objOf([
  5348. fFactory,
  5349. fSchema,
  5350. fName,
  5351. fPname,
  5352. fDefaults,
  5353. fOverrides
  5354. ]);
  5355. const externalSpec = objOf([
  5356. fFactory,
  5357. fSchema,
  5358. fName,
  5359. fDefaults,
  5360. fOverrides
  5361. ]);
  5362. const optionalSpec = objOf([
  5363. fFactory,
  5364. fSchema,
  5365. fName,
  5366. fPname,
  5367. fDefaults,
  5368. fOverrides
  5369. ]);
  5370. const groupSpec = objOf([
  5371. fFactory,
  5372. fGroupSchema,
  5373. fName,
  5374. required$1('unit'),
  5375. fPname,
  5376. fDefaults,
  5377. fOverrides
  5378. ]);
  5379. const asNamedPart = part => {
  5380. return part.fold(Optional.some, Optional.none, Optional.some, Optional.some);
  5381. };
  5382. const name$2 = part => {
  5383. const get = data => data.name;
  5384. return part.fold(get, get, get, get);
  5385. };
  5386. const asCommon = part => {
  5387. return part.fold(identity, identity, identity, identity);
  5388. };
  5389. const convert = (adtConstructor, partSchema) => spec => {
  5390. const data = asRawOrDie$1('Converting part type', partSchema, spec);
  5391. return adtConstructor(data);
  5392. };
  5393. const required = convert(adt$2.required, requiredSpec);
  5394. const external = convert(adt$2.external, externalSpec);
  5395. const optional = convert(adt$2.optional, optionalSpec);
  5396. const group = convert(adt$2.group, groupSpec);
  5397. const original = constant$1('entirety');
  5398. var PartType = /*#__PURE__*/Object.freeze({
  5399. __proto__: null,
  5400. required: required,
  5401. external: external,
  5402. optional: optional,
  5403. group: group,
  5404. asNamedPart: asNamedPart,
  5405. name: name$2,
  5406. asCommon: asCommon,
  5407. original: original
  5408. });
  5409. const combine = (detail, data, partSpec, partValidated) => deepMerge(data.defaults(detail, partSpec, partValidated), partSpec, { uid: detail.partUids[data.name] }, data.overrides(detail, partSpec, partValidated));
  5410. const subs = (owner, detail, parts) => {
  5411. const internals = {};
  5412. const externals = {};
  5413. each$1(parts, part => {
  5414. part.fold(data => {
  5415. internals[data.pname] = single$2(true, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
  5416. }, data => {
  5417. const partSpec = detail.parts[data.name];
  5418. externals[data.name] = constant$1(data.factory.sketch(combine(detail, data, partSpec[original()]), partSpec));
  5419. }, data => {
  5420. internals[data.pname] = single$2(false, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
  5421. }, data => {
  5422. internals[data.pname] = multiple(true, (detail, _partSpec, _partValidated) => {
  5423. const units = detail[data.name];
  5424. return map$2(units, u => data.factory.sketch(deepMerge(data.defaults(detail, u, _partValidated), u, data.overrides(detail, u))));
  5425. });
  5426. });
  5427. });
  5428. return {
  5429. internals: constant$1(internals),
  5430. externals: constant$1(externals)
  5431. };
  5432. };
  5433. const generate$3 = (owner, parts) => {
  5434. const r = {};
  5435. each$1(parts, part => {
  5436. asNamedPart(part).each(np => {
  5437. const g = doGenerateOne(owner, np.pname);
  5438. r[np.name] = config => {
  5439. const validated = asRawOrDie$1('Part: ' + np.name + ' in ' + owner, objOf(np.schema), config);
  5440. return {
  5441. ...g,
  5442. config,
  5443. validated
  5444. };
  5445. };
  5446. });
  5447. });
  5448. return r;
  5449. };
  5450. const doGenerateOne = (owner, pname) => ({
  5451. uiType: placeholder(),
  5452. owner,
  5453. name: pname
  5454. });
  5455. const generateOne$1 = (owner, pname, config) => ({
  5456. uiType: placeholder(),
  5457. owner,
  5458. name: pname,
  5459. config,
  5460. validated: {}
  5461. });
  5462. const schemas = parts => bind$3(parts, part => part.fold(Optional.none, Optional.some, Optional.none, Optional.none).map(data => requiredObjOf(data.name, data.schema.concat([snapshot(original())]))).toArray());
  5463. const names = parts => map$2(parts, name$2);
  5464. const substitutes = (owner, detail, parts) => subs(owner, detail, parts);
  5465. const components$1 = (owner, detail, internals) => substitutePlaces(Optional.some(owner), detail, detail.components, internals);
  5466. const getPart = (component, detail, partKey) => {
  5467. const uid = detail.partUids[partKey];
  5468. return component.getSystem().getByUid(uid).toOptional();
  5469. };
  5470. const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey);
  5471. const getParts = (component, detail, partKeys) => {
  5472. const r = {};
  5473. const uids = detail.partUids;
  5474. const system = component.getSystem();
  5475. each$1(partKeys, pk => {
  5476. r[pk] = constant$1(system.getByUid(uids[pk]));
  5477. });
  5478. return r;
  5479. };
  5480. const getAllParts = (component, detail) => {
  5481. const system = component.getSystem();
  5482. return map$1(detail.partUids, (pUid, _k) => constant$1(system.getByUid(pUid)));
  5483. };
  5484. const getAllPartNames = detail => keys(detail.partUids);
  5485. const getPartsOrDie = (component, detail, partKeys) => {
  5486. const r = {};
  5487. const uids = detail.partUids;
  5488. const system = component.getSystem();
  5489. each$1(partKeys, pk => {
  5490. r[pk] = constant$1(system.getByUid(uids[pk]).getOrDie());
  5491. });
  5492. return r;
  5493. };
  5494. const defaultUids = (baseUid, partTypes) => {
  5495. const partNames = names(partTypes);
  5496. return wrapAll(map$2(partNames, pn => ({
  5497. key: pn,
  5498. value: baseUid + '-' + pn
  5499. })));
  5500. };
  5501. const defaultUidsSchema = partTypes => field$1('partUids', 'partUids', mergeWithThunk(spec => defaultUids(spec.uid, partTypes)), anyValue());
  5502. var AlloyParts = /*#__PURE__*/Object.freeze({
  5503. __proto__: null,
  5504. generate: generate$3,
  5505. generateOne: generateOne$1,
  5506. schemas: schemas,
  5507. names: names,
  5508. substitutes: substitutes,
  5509. components: components$1,
  5510. defaultUids: defaultUids,
  5511. defaultUidsSchema: defaultUidsSchema,
  5512. getAllParts: getAllParts,
  5513. getAllPartNames: getAllPartNames,
  5514. getPart: getPart,
  5515. getPartOrDie: getPartOrDie,
  5516. getParts: getParts,
  5517. getPartsOrDie: getPartsOrDie
  5518. });
  5519. const base = (partSchemas, partUidsSchemas) => {
  5520. const ps = partSchemas.length > 0 ? [requiredObjOf('parts', partSchemas)] : [];
  5521. return ps.concat([
  5522. required$1('uid'),
  5523. defaulted('dom', {}),
  5524. defaulted('components', []),
  5525. snapshot('originalSpec'),
  5526. defaulted('debug.sketcher', {})
  5527. ]).concat(partUidsSchemas);
  5528. };
  5529. const asRawOrDie = (label, schema, spec, partSchemas, partUidsSchemas) => {
  5530. const baseS = base(partSchemas, partUidsSchemas);
  5531. return asRawOrDie$1(label + ' [SpecSchema]', objOfOnly(baseS.concat(schema)), spec);
  5532. };
  5533. const single$1 = (owner, schema, factory, spec) => {
  5534. const specWithUid = supplyUid(spec);
  5535. const detail = asRawOrDie(owner, schema, specWithUid, [], []);
  5536. return factory(detail, specWithUid);
  5537. };
  5538. const composite$1 = (owner, schema, partTypes, factory, spec) => {
  5539. const specWithUid = supplyUid(spec);
  5540. const partSchemas = schemas(partTypes);
  5541. const partUidsSchema = defaultUidsSchema(partTypes);
  5542. const detail = asRawOrDie(owner, schema, specWithUid, partSchemas, [partUidsSchema]);
  5543. const subs = substitutes(owner, detail, partTypes);
  5544. const components = components$1(owner, detail, subs.internals());
  5545. return factory(detail, components, specWithUid, subs.externals());
  5546. };
  5547. const hasUid = spec => has$2(spec, 'uid');
  5548. const supplyUid = spec => {
  5549. return hasUid(spec) ? spec : {
  5550. ...spec,
  5551. uid: generate$5('uid')
  5552. };
  5553. };
  5554. const isSketchSpec = spec => {
  5555. return spec.uid !== undefined;
  5556. };
  5557. const singleSchema = objOfOnly([
  5558. required$1('name'),
  5559. required$1('factory'),
  5560. required$1('configFields'),
  5561. defaulted('apis', {}),
  5562. defaulted('extraApis', {})
  5563. ]);
  5564. const compositeSchema = objOfOnly([
  5565. required$1('name'),
  5566. required$1('factory'),
  5567. required$1('configFields'),
  5568. required$1('partFields'),
  5569. defaulted('apis', {}),
  5570. defaulted('extraApis', {})
  5571. ]);
  5572. const single = rawConfig => {
  5573. const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, singleSchema, rawConfig);
  5574. const sketch = spec => single$1(config.name, config.configFields, config.factory, spec);
  5575. const apis = map$1(config.apis, makeApi);
  5576. const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
  5577. return {
  5578. name: config.name,
  5579. configFields: config.configFields,
  5580. sketch,
  5581. ...apis,
  5582. ...extraApis
  5583. };
  5584. };
  5585. const composite = rawConfig => {
  5586. const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig);
  5587. const sketch = spec => composite$1(config.name, config.configFields, config.partFields, config.factory, spec);
  5588. const parts = generate$3(config.name, config.partFields);
  5589. const apis = map$1(config.apis, makeApi);
  5590. const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
  5591. return {
  5592. name: config.name,
  5593. partFields: config.partFields,
  5594. configFields: config.configFields,
  5595. sketch,
  5596. parts,
  5597. ...apis,
  5598. ...extraApis
  5599. };
  5600. };
  5601. const inside = target => isTag('input')(target) && get$f(target, 'type') !== 'radio' || isTag('textarea')(target);
  5602. const getCurrent = (component, composeConfig, _composeState) => composeConfig.find(component);
  5603. var ComposeApis = /*#__PURE__*/Object.freeze({
  5604. __proto__: null,
  5605. getCurrent: getCurrent
  5606. });
  5607. const ComposeSchema = [required$1('find')];
  5608. const Composing = create$4({
  5609. fields: ComposeSchema,
  5610. name: 'composing',
  5611. apis: ComposeApis
  5612. });
  5613. const nativeDisabled = [
  5614. 'input',
  5615. 'button',
  5616. 'textarea',
  5617. 'select'
  5618. ];
  5619. const onLoad$1 = (component, disableConfig, disableState) => {
  5620. const f = disableConfig.disabled() ? disable : enable;
  5621. f(component, disableConfig);
  5622. };
  5623. const hasNative = (component, config) => config.useNative === true && contains$2(nativeDisabled, name$3(component.element));
  5624. const nativeIsDisabled = component => has$1(component.element, 'disabled');
  5625. const nativeDisable = component => {
  5626. set$9(component.element, 'disabled', 'disabled');
  5627. };
  5628. const nativeEnable = component => {
  5629. remove$7(component.element, 'disabled');
  5630. };
  5631. const ariaIsDisabled = component => get$f(component.element, 'aria-disabled') === 'true';
  5632. const ariaDisable = component => {
  5633. set$9(component.element, 'aria-disabled', 'true');
  5634. };
  5635. const ariaEnable = component => {
  5636. set$9(component.element, 'aria-disabled', 'false');
  5637. };
  5638. const disable = (component, disableConfig, _disableState) => {
  5639. disableConfig.disableClass.each(disableClass => {
  5640. add$2(component.element, disableClass);
  5641. });
  5642. const f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable;
  5643. f(component);
  5644. disableConfig.onDisabled(component);
  5645. };
  5646. const enable = (component, disableConfig, _disableState) => {
  5647. disableConfig.disableClass.each(disableClass => {
  5648. remove$2(component.element, disableClass);
  5649. });
  5650. const f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable;
  5651. f(component);
  5652. disableConfig.onEnabled(component);
  5653. };
  5654. const isDisabled = (component, disableConfig) => hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component);
  5655. const set$4 = (component, disableConfig, disableState, disabled) => {
  5656. const f = disabled ? disable : enable;
  5657. f(component, disableConfig);
  5658. };
  5659. var DisableApis = /*#__PURE__*/Object.freeze({
  5660. __proto__: null,
  5661. enable: enable,
  5662. disable: disable,
  5663. isDisabled: isDisabled,
  5664. onLoad: onLoad$1,
  5665. set: set$4
  5666. });
  5667. const exhibit$5 = (base, disableConfig) => nu$7({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] });
  5668. const events$e = (disableConfig, disableState) => derive$2([
  5669. abort(execute$5(), (component, _simulatedEvent) => isDisabled(component, disableConfig)),
  5670. loadEvent(disableConfig, disableState, onLoad$1)
  5671. ]);
  5672. var ActiveDisable = /*#__PURE__*/Object.freeze({
  5673. __proto__: null,
  5674. exhibit: exhibit$5,
  5675. events: events$e
  5676. });
  5677. var DisableSchema = [
  5678. defaultedFunction('disabled', never),
  5679. defaulted('useNative', true),
  5680. option$3('disableClass'),
  5681. onHandler('onDisabled'),
  5682. onHandler('onEnabled')
  5683. ];
  5684. const Disabling = create$4({
  5685. fields: DisableSchema,
  5686. name: 'disabling',
  5687. active: ActiveDisable,
  5688. apis: DisableApis
  5689. });
  5690. const dehighlightAllExcept = (component, hConfig, hState, skip) => {
  5691. const highlighted = descendants(component.element, '.' + hConfig.highlightClass);
  5692. each$1(highlighted, h => {
  5693. const shouldSkip = exists(skip, skipComp => eq(skipComp.element, h));
  5694. if (!shouldSkip) {
  5695. remove$2(h, hConfig.highlightClass);
  5696. component.getSystem().getByDom(h).each(target => {
  5697. hConfig.onDehighlight(component, target);
  5698. emit(target, dehighlight$1());
  5699. });
  5700. }
  5701. });
  5702. };
  5703. const dehighlightAll = (component, hConfig, hState) => dehighlightAllExcept(component, hConfig, hState, []);
  5704. const dehighlight = (component, hConfig, hState, target) => {
  5705. if (isHighlighted(component, hConfig, hState, target)) {
  5706. remove$2(target.element, hConfig.highlightClass);
  5707. hConfig.onDehighlight(component, target);
  5708. emit(target, dehighlight$1());
  5709. }
  5710. };
  5711. const highlight = (component, hConfig, hState, target) => {
  5712. dehighlightAllExcept(component, hConfig, hState, [target]);
  5713. if (!isHighlighted(component, hConfig, hState, target)) {
  5714. add$2(target.element, hConfig.highlightClass);
  5715. hConfig.onHighlight(component, target);
  5716. emit(target, highlight$1());
  5717. }
  5718. };
  5719. const highlightFirst = (component, hConfig, hState) => {
  5720. getFirst(component, hConfig).each(firstComp => {
  5721. highlight(component, hConfig, hState, firstComp);
  5722. });
  5723. };
  5724. const highlightLast = (component, hConfig, hState) => {
  5725. getLast(component, hConfig).each(lastComp => {
  5726. highlight(component, hConfig, hState, lastComp);
  5727. });
  5728. };
  5729. const highlightAt = (component, hConfig, hState, index) => {
  5730. getByIndex(component, hConfig, hState, index).fold(err => {
  5731. throw err;
  5732. }, firstComp => {
  5733. highlight(component, hConfig, hState, firstComp);
  5734. });
  5735. };
  5736. const highlightBy = (component, hConfig, hState, predicate) => {
  5737. const candidates = getCandidates(component, hConfig);
  5738. const targetComp = find$5(candidates, predicate);
  5739. targetComp.each(c => {
  5740. highlight(component, hConfig, hState, c);
  5741. });
  5742. };
  5743. const isHighlighted = (component, hConfig, hState, queryTarget) => has(queryTarget.element, hConfig.highlightClass);
  5744. const getHighlighted = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.highlightClass).bind(e => component.getSystem().getByDom(e).toOptional());
  5745. const getByIndex = (component, hConfig, hState, index) => {
  5746. const items = descendants(component.element, '.' + hConfig.itemClass);
  5747. return Optional.from(items[index]).fold(() => Result.error(new Error('No element found with index ' + index)), component.getSystem().getByDom);
  5748. };
  5749. const getFirst = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.itemClass).bind(e => component.getSystem().getByDom(e).toOptional());
  5750. const getLast = (component, hConfig, _hState) => {
  5751. const items = descendants(component.element, '.' + hConfig.itemClass);
  5752. const last = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none();
  5753. return last.bind(c => component.getSystem().getByDom(c).toOptional());
  5754. };
  5755. const getDelta$2 = (component, hConfig, hState, delta) => {
  5756. const items = descendants(component.element, '.' + hConfig.itemClass);
  5757. const current = findIndex$1(items, item => has(item, hConfig.highlightClass));
  5758. return current.bind(selected => {
  5759. const dest = cycleBy(selected, delta, 0, items.length - 1);
  5760. return component.getSystem().getByDom(items[dest]).toOptional();
  5761. });
  5762. };
  5763. const getPrevious = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, -1);
  5764. const getNext = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, +1);
  5765. const getCandidates = (component, hConfig, _hState) => {
  5766. const items = descendants(component.element, '.' + hConfig.itemClass);
  5767. return cat(map$2(items, i => component.getSystem().getByDom(i).toOptional()));
  5768. };
  5769. var HighlightApis = /*#__PURE__*/Object.freeze({
  5770. __proto__: null,
  5771. dehighlightAll: dehighlightAll,
  5772. dehighlight: dehighlight,
  5773. highlight: highlight,
  5774. highlightFirst: highlightFirst,
  5775. highlightLast: highlightLast,
  5776. highlightAt: highlightAt,
  5777. highlightBy: highlightBy,
  5778. isHighlighted: isHighlighted,
  5779. getHighlighted: getHighlighted,
  5780. getFirst: getFirst,
  5781. getLast: getLast,
  5782. getPrevious: getPrevious,
  5783. getNext: getNext,
  5784. getCandidates: getCandidates
  5785. });
  5786. var HighlightSchema = [
  5787. required$1('highlightClass'),
  5788. required$1('itemClass'),
  5789. onHandler('onHighlight'),
  5790. onHandler('onDehighlight')
  5791. ];
  5792. const Highlighting = create$4({
  5793. fields: HighlightSchema,
  5794. name: 'highlighting',
  5795. apis: HighlightApis
  5796. });
  5797. const BACKSPACE = [8];
  5798. const TAB = [9];
  5799. const ENTER = [13];
  5800. const ESCAPE = [27];
  5801. const SPACE = [32];
  5802. const LEFT = [37];
  5803. const UP = [38];
  5804. const RIGHT = [39];
  5805. const DOWN = [40];
  5806. const cyclePrev = (values, index, predicate) => {
  5807. const before = reverse(values.slice(0, index));
  5808. const after = reverse(values.slice(index + 1));
  5809. return find$5(before.concat(after), predicate);
  5810. };
  5811. const tryPrev = (values, index, predicate) => {
  5812. const before = reverse(values.slice(0, index));
  5813. return find$5(before, predicate);
  5814. };
  5815. const cycleNext = (values, index, predicate) => {
  5816. const before = values.slice(0, index);
  5817. const after = values.slice(index + 1);
  5818. return find$5(after.concat(before), predicate);
  5819. };
  5820. const tryNext = (values, index, predicate) => {
  5821. const after = values.slice(index + 1);
  5822. return find$5(after, predicate);
  5823. };
  5824. const inSet = keys => event => {
  5825. const raw = event.raw;
  5826. return contains$2(keys, raw.which);
  5827. };
  5828. const and = preds => event => forall(preds, pred => pred(event));
  5829. const isShift$1 = event => {
  5830. const raw = event.raw;
  5831. return raw.shiftKey === true;
  5832. };
  5833. const isControl = event => {
  5834. const raw = event.raw;
  5835. return raw.ctrlKey === true;
  5836. };
  5837. const isNotShift = not(isShift$1);
  5838. const rule = (matches, action) => ({
  5839. matches,
  5840. classification: action
  5841. });
  5842. const choose = (transitions, event) => {
  5843. const transition = find$5(transitions, t => t.matches(event));
  5844. return transition.map(t => t.classification);
  5845. };
  5846. const reportFocusShifting = (component, prevFocus, newFocus) => {
  5847. const noChange = prevFocus.exists(p => newFocus.exists(n => eq(n, p)));
  5848. if (!noChange) {
  5849. emitWith(component, focusShifted(), {
  5850. prevFocus,
  5851. newFocus
  5852. });
  5853. }
  5854. };
  5855. const dom$2 = () => {
  5856. const get = component => search(component.element);
  5857. const set = (component, focusee) => {
  5858. const prevFocus = get(component);
  5859. component.getSystem().triggerFocus(focusee, component.element);
  5860. const newFocus = get(component);
  5861. reportFocusShifting(component, prevFocus, newFocus);
  5862. };
  5863. return {
  5864. get,
  5865. set
  5866. };
  5867. };
  5868. const highlights = () => {
  5869. const get = component => Highlighting.getHighlighted(component).map(item => item.element);
  5870. const set = (component, element) => {
  5871. const prevFocus = get(component);
  5872. component.getSystem().getByDom(element).fold(noop, item => {
  5873. Highlighting.highlight(component, item);
  5874. });
  5875. const newFocus = get(component);
  5876. reportFocusShifting(component, prevFocus, newFocus);
  5877. };
  5878. return {
  5879. get,
  5880. set
  5881. };
  5882. };
  5883. var FocusInsideModes;
  5884. (function (FocusInsideModes) {
  5885. FocusInsideModes['OnFocusMode'] = 'onFocus';
  5886. FocusInsideModes['OnEnterOrSpaceMode'] = 'onEnterOrSpace';
  5887. FocusInsideModes['OnApiMode'] = 'onApi';
  5888. }(FocusInsideModes || (FocusInsideModes = {})));
  5889. const typical = (infoSchema, stateInit, getKeydownRules, getKeyupRules, optFocusIn) => {
  5890. const schema = () => infoSchema.concat([
  5891. defaulted('focusManager', dom$2()),
  5892. defaultedOf('focusInside', 'onFocus', valueOf(val => contains$2([
  5893. 'onFocus',
  5894. 'onEnterOrSpace',
  5895. 'onApi'
  5896. ], val) ? Result.value(val) : Result.error('Invalid value for focusInside'))),
  5897. output$1('handler', me),
  5898. output$1('state', stateInit),
  5899. output$1('sendFocusIn', optFocusIn)
  5900. ]);
  5901. const processKey = (component, simulatedEvent, getRules, keyingConfig, keyingState) => {
  5902. const rules = getRules(component, simulatedEvent, keyingConfig, keyingState);
  5903. return choose(rules, simulatedEvent.event).bind(rule => rule(component, simulatedEvent, keyingConfig, keyingState));
  5904. };
  5905. const toEvents = (keyingConfig, keyingState) => {
  5906. const onFocusHandler = keyingConfig.focusInside !== FocusInsideModes.OnFocusMode ? Optional.none() : optFocusIn(keyingConfig).map(focusIn => run$1(focus$4(), (component, simulatedEvent) => {
  5907. focusIn(component, keyingConfig, keyingState);
  5908. simulatedEvent.stop();
  5909. }));
  5910. const tryGoInsideComponent = (component, simulatedEvent) => {
  5911. const isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event);
  5912. if (keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode && isEnterOrSpace && isSource(component, simulatedEvent)) {
  5913. optFocusIn(keyingConfig).each(focusIn => {
  5914. focusIn(component, keyingConfig, keyingState);
  5915. simulatedEvent.stop();
  5916. });
  5917. }
  5918. };
  5919. const keyboardEvents = [
  5920. run$1(keydown(), (component, simulatedEvent) => {
  5921. processKey(component, simulatedEvent, getKeydownRules, keyingConfig, keyingState).fold(() => {
  5922. tryGoInsideComponent(component, simulatedEvent);
  5923. }, _ => {
  5924. simulatedEvent.stop();
  5925. });
  5926. }),
  5927. run$1(keyup(), (component, simulatedEvent) => {
  5928. processKey(component, simulatedEvent, getKeyupRules, keyingConfig, keyingState).each(_ => {
  5929. simulatedEvent.stop();
  5930. });
  5931. })
  5932. ];
  5933. return derive$2(onFocusHandler.toArray().concat(keyboardEvents));
  5934. };
  5935. const me = {
  5936. schema,
  5937. processKey,
  5938. toEvents
  5939. };
  5940. return me;
  5941. };
  5942. const create$2 = cyclicField => {
  5943. const schema = [
  5944. option$3('onEscape'),
  5945. option$3('onEnter'),
  5946. defaulted('selector', '[data-alloy-tabstop="true"]:not(:disabled)'),
  5947. defaulted('firstTabstop', 0),
  5948. defaulted('useTabstopAt', always),
  5949. option$3('visibilitySelector')
  5950. ].concat([cyclicField]);
  5951. const isVisible = (tabbingConfig, element) => {
  5952. const target = tabbingConfig.visibilitySelector.bind(sel => closest$1(element, sel)).getOr(element);
  5953. return get$d(target) > 0;
  5954. };
  5955. const findInitial = (component, tabbingConfig) => {
  5956. const tabstops = descendants(component.element, tabbingConfig.selector);
  5957. const visibles = filter$2(tabstops, elem => isVisible(tabbingConfig, elem));
  5958. return Optional.from(visibles[tabbingConfig.firstTabstop]);
  5959. };
  5960. const findCurrent = (component, tabbingConfig) => tabbingConfig.focusManager.get(component).bind(elem => closest$1(elem, tabbingConfig.selector));
  5961. const isTabstop = (tabbingConfig, element) => isVisible(tabbingConfig, element) && tabbingConfig.useTabstopAt(element);
  5962. const focusIn = (component, tabbingConfig, _tabbingState) => {
  5963. findInitial(component, tabbingConfig).each(target => {
  5964. tabbingConfig.focusManager.set(component, target);
  5965. });
  5966. };
  5967. const goFromTabstop = (component, tabstops, stopIndex, tabbingConfig, cycle) => cycle(tabstops, stopIndex, elem => isTabstop(tabbingConfig, elem)).fold(() => tabbingConfig.cyclic ? Optional.some(true) : Optional.none(), target => {
  5968. tabbingConfig.focusManager.set(component, target);
  5969. return Optional.some(true);
  5970. });
  5971. const go = (component, _simulatedEvent, tabbingConfig, cycle) => {
  5972. const tabstops = descendants(component.element, tabbingConfig.selector);
  5973. return findCurrent(component, tabbingConfig).bind(tabstop => {
  5974. const optStopIndex = findIndex$1(tabstops, curry(eq, tabstop));
  5975. return optStopIndex.bind(stopIndex => goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle));
  5976. });
  5977. };
  5978. const goBackwards = (component, simulatedEvent, tabbingConfig) => {
  5979. const navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev;
  5980. return go(component, simulatedEvent, tabbingConfig, navigate);
  5981. };
  5982. const goForwards = (component, simulatedEvent, tabbingConfig) => {
  5983. const navigate = tabbingConfig.cyclic ? cycleNext : tryNext;
  5984. return go(component, simulatedEvent, tabbingConfig, navigate);
  5985. };
  5986. const isFirstChild = elem => parentNode(elem).bind(firstChild).exists(child => eq(child, elem));
  5987. const goFromPseudoTabstop = (component, simulatedEvent, tabbingConfig) => findCurrent(component, tabbingConfig).filter(elem => !tabbingConfig.useTabstopAt(elem)).bind(elem => (isFirstChild(elem) ? goBackwards : goForwards)(component, simulatedEvent, tabbingConfig));
  5988. const execute = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEnter.bind(f => f(component, simulatedEvent));
  5989. const exit = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEscape.bind(f => f(component, simulatedEvent));
  5990. const getKeydownRules = constant$1([
  5991. rule(and([
  5992. isShift$1,
  5993. inSet(TAB)
  5994. ]), goBackwards),
  5995. rule(inSet(TAB), goForwards),
  5996. rule(and([
  5997. isNotShift,
  5998. inSet(ENTER)
  5999. ]), execute)
  6000. ]);
  6001. const getKeyupRules = constant$1([
  6002. rule(inSet(ESCAPE), exit),
  6003. rule(inSet(TAB), goFromPseudoTabstop)
  6004. ]);
  6005. return typical(schema, NoState.init, getKeydownRules, getKeyupRules, () => Optional.some(focusIn));
  6006. };
  6007. var AcyclicType = create$2(customField('cyclic', never));
  6008. var CyclicType = create$2(customField('cyclic', always));
  6009. const doDefaultExecute = (component, _simulatedEvent, focused) => {
  6010. dispatch(component, focused, execute$5());
  6011. return Optional.some(true);
  6012. };
  6013. const defaultExecute = (component, simulatedEvent, focused) => {
  6014. const isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event);
  6015. return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused);
  6016. };
  6017. const stopEventForFirefox = (_component, _simulatedEvent) => Optional.some(true);
  6018. const schema$v = [
  6019. defaulted('execute', defaultExecute),
  6020. defaulted('useSpace', false),
  6021. defaulted('useEnter', true),
  6022. defaulted('useControlEnter', false),
  6023. defaulted('useDown', false)
  6024. ];
  6025. const execute$4 = (component, simulatedEvent, executeConfig) => executeConfig.execute(component, simulatedEvent, component.element);
  6026. const getKeydownRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => {
  6027. const spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : [];
  6028. const enterExec = executeConfig.useEnter ? ENTER : [];
  6029. const downExec = executeConfig.useDown ? DOWN : [];
  6030. const execKeys = spaceExec.concat(enterExec).concat(downExec);
  6031. return [rule(inSet(execKeys), execute$4)].concat(executeConfig.useControlEnter ? [rule(and([
  6032. isControl,
  6033. inSet(ENTER)
  6034. ]), execute$4)] : []);
  6035. };
  6036. const getKeyupRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : [];
  6037. var ExecutionType = typical(schema$v, NoState.init, getKeydownRules$5, getKeyupRules$5, () => Optional.none());
  6038. const flatgrid$1 = () => {
  6039. const dimensions = value$2();
  6040. const setGridSize = (numRows, numColumns) => {
  6041. dimensions.set({
  6042. numRows,
  6043. numColumns
  6044. });
  6045. };
  6046. const getNumRows = () => dimensions.get().map(d => d.numRows);
  6047. const getNumColumns = () => dimensions.get().map(d => d.numColumns);
  6048. return nu$8({
  6049. readState: () => dimensions.get().map(d => ({
  6050. numRows: String(d.numRows),
  6051. numColumns: String(d.numColumns)
  6052. })).getOr({
  6053. numRows: '?',
  6054. numColumns: '?'
  6055. }),
  6056. setGridSize,
  6057. getNumRows,
  6058. getNumColumns
  6059. });
  6060. };
  6061. const init$d = spec => spec.state(spec);
  6062. var KeyingState = /*#__PURE__*/Object.freeze({
  6063. __proto__: null,
  6064. flatgrid: flatgrid$1,
  6065. init: init$d
  6066. });
  6067. const useH = movement => (component, simulatedEvent, config, state) => {
  6068. const move = movement(component.element);
  6069. return use(move, component, simulatedEvent, config, state);
  6070. };
  6071. const west$1 = (moveLeft, moveRight) => {
  6072. const movement = onDirection(moveLeft, moveRight);
  6073. return useH(movement);
  6074. };
  6075. const east$1 = (moveLeft, moveRight) => {
  6076. const movement = onDirection(moveRight, moveLeft);
  6077. return useH(movement);
  6078. };
  6079. const useV = move => (component, simulatedEvent, config, state) => use(move, component, simulatedEvent, config, state);
  6080. const use = (move, component, simulatedEvent, config, state) => {
  6081. const outcome = config.focusManager.get(component).bind(focused => move(component.element, focused, config, state));
  6082. return outcome.map(newFocus => {
  6083. config.focusManager.set(component, newFocus);
  6084. return true;
  6085. });
  6086. };
  6087. const north$1 = useV;
  6088. const south$1 = useV;
  6089. const move$1 = useV;
  6090. const isHidden$1 = dom => dom.offsetWidth <= 0 && dom.offsetHeight <= 0;
  6091. const isVisible = element => !isHidden$1(element.dom);
  6092. const locate = (candidates, predicate) => findIndex$1(candidates, predicate).map(index => ({
  6093. index,
  6094. candidates
  6095. }));
  6096. const locateVisible = (container, current, selector) => {
  6097. const predicate = x => eq(x, current);
  6098. const candidates = descendants(container, selector);
  6099. const visible = filter$2(candidates, isVisible);
  6100. return locate(visible, predicate);
  6101. };
  6102. const findIndex = (elements, target) => findIndex$1(elements, elem => eq(target, elem));
  6103. const withGrid = (values, index, numCols, f) => {
  6104. const oldRow = Math.floor(index / numCols);
  6105. const oldColumn = index % numCols;
  6106. return f(oldRow, oldColumn).bind(address => {
  6107. const newIndex = address.row * numCols + address.column;
  6108. return newIndex >= 0 && newIndex < values.length ? Optional.some(values[newIndex]) : Optional.none();
  6109. });
  6110. };
  6111. const cycleHorizontal$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
  6112. const onLastRow = oldRow === numRows - 1;
  6113. const colsInRow = onLastRow ? values.length - oldRow * numCols : numCols;
  6114. const newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1);
  6115. return Optional.some({
  6116. row: oldRow,
  6117. column: newColumn
  6118. });
  6119. });
  6120. const cycleVertical$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
  6121. const newRow = cycleBy(oldRow, delta, 0, numRows - 1);
  6122. const onLastRow = newRow === numRows - 1;
  6123. const colsInRow = onLastRow ? values.length - newRow * numCols : numCols;
  6124. const newCol = clamp(oldColumn, 0, colsInRow - 1);
  6125. return Optional.some({
  6126. row: newRow,
  6127. column: newCol
  6128. });
  6129. });
  6130. const cycleRight$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, +1);
  6131. const cycleLeft$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, -1);
  6132. const cycleUp$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, -1);
  6133. const cycleDown$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, +1);
  6134. const schema$u = [
  6135. required$1('selector'),
  6136. defaulted('execute', defaultExecute),
  6137. onKeyboardHandler('onEscape'),
  6138. defaulted('captureTab', false),
  6139. initSize()
  6140. ];
  6141. const focusIn$3 = (component, gridConfig, _gridState) => {
  6142. descendant(component.element, gridConfig.selector).each(first => {
  6143. gridConfig.focusManager.set(component, first);
  6144. });
  6145. };
  6146. const findCurrent$1 = (component, gridConfig) => gridConfig.focusManager.get(component).bind(elem => closest$1(elem, gridConfig.selector));
  6147. const execute$3 = (component, simulatedEvent, gridConfig, _gridState) => findCurrent$1(component, gridConfig).bind(focused => gridConfig.execute(component, simulatedEvent, focused));
  6148. const doMove$2 = cycle => (element, focused, gridConfig, gridState) => locateVisible(element, focused, gridConfig.selector).bind(identified => cycle(identified.candidates, identified.index, gridState.getNumRows().getOr(gridConfig.initSize.numRows), gridState.getNumColumns().getOr(gridConfig.initSize.numColumns)));
  6149. const handleTab = (_component, _simulatedEvent, gridConfig) => gridConfig.captureTab ? Optional.some(true) : Optional.none();
  6150. const doEscape$1 = (component, simulatedEvent, gridConfig) => gridConfig.onEscape(component, simulatedEvent);
  6151. const moveLeft$3 = doMove$2(cycleLeft$1);
  6152. const moveRight$3 = doMove$2(cycleRight$1);
  6153. const moveNorth$1 = doMove$2(cycleUp$1);
  6154. const moveSouth$1 = doMove$2(cycleDown$1);
  6155. const getKeydownRules$4 = constant$1([
  6156. rule(inSet(LEFT), west$1(moveLeft$3, moveRight$3)),
  6157. rule(inSet(RIGHT), east$1(moveLeft$3, moveRight$3)),
  6158. rule(inSet(UP), north$1(moveNorth$1)),
  6159. rule(inSet(DOWN), south$1(moveSouth$1)),
  6160. rule(and([
  6161. isShift$1,
  6162. inSet(TAB)
  6163. ]), handleTab),
  6164. rule(and([
  6165. isNotShift,
  6166. inSet(TAB)
  6167. ]), handleTab),
  6168. rule(inSet(SPACE.concat(ENTER)), execute$3)
  6169. ]);
  6170. const getKeyupRules$4 = constant$1([
  6171. rule(inSet(ESCAPE), doEscape$1),
  6172. rule(inSet(SPACE), stopEventForFirefox)
  6173. ]);
  6174. var FlatgridType = typical(schema$u, flatgrid$1, getKeydownRules$4, getKeyupRules$4, () => Optional.some(focusIn$3));
  6175. const f = (container, selector, current, delta, getNewIndex) => {
  6176. const isDisabledButton = candidate => name$3(candidate) === 'button' && get$f(candidate, 'disabled') === 'disabled';
  6177. const tryNewIndex = (initial, index, candidates) => getNewIndex(initial, index, delta, 0, candidates.length - 1, candidates[index], newIndex => isDisabledButton(candidates[newIndex]) ? tryNewIndex(initial, newIndex, candidates) : Optional.from(candidates[newIndex]));
  6178. return locateVisible(container, current, selector).bind(identified => {
  6179. const index = identified.index;
  6180. const candidates = identified.candidates;
  6181. return tryNewIndex(index, index, candidates);
  6182. });
  6183. };
  6184. const horizontalWithoutCycles = (container, selector, current, delta) => f(container, selector, current, delta, (prevIndex, v, d, min, max, oldCandidate, onNewIndex) => {
  6185. const newIndex = clamp(v + d, min, max);
  6186. return newIndex === prevIndex ? Optional.from(oldCandidate) : onNewIndex(newIndex);
  6187. });
  6188. const horizontal = (container, selector, current, delta) => f(container, selector, current, delta, (prevIndex, v, d, min, max, _oldCandidate, onNewIndex) => {
  6189. const newIndex = cycleBy(v, d, min, max);
  6190. return newIndex === prevIndex ? Optional.none() : onNewIndex(newIndex);
  6191. });
  6192. const schema$t = [
  6193. required$1('selector'),
  6194. defaulted('getInitial', Optional.none),
  6195. defaulted('execute', defaultExecute),
  6196. onKeyboardHandler('onEscape'),
  6197. defaulted('executeOnMove', false),
  6198. defaulted('allowVertical', true),
  6199. defaulted('allowHorizontal', true),
  6200. defaulted('cycles', true)
  6201. ];
  6202. const findCurrent = (component, flowConfig) => flowConfig.focusManager.get(component).bind(elem => closest$1(elem, flowConfig.selector));
  6203. const execute$2 = (component, simulatedEvent, flowConfig) => findCurrent(component, flowConfig).bind(focused => flowConfig.execute(component, simulatedEvent, focused));
  6204. const focusIn$2 = (component, flowConfig, _state) => {
  6205. flowConfig.getInitial(component).orThunk(() => descendant(component.element, flowConfig.selector)).each(first => {
  6206. flowConfig.focusManager.set(component, first);
  6207. });
  6208. };
  6209. const moveLeft$2 = (element, focused, info) => (info.cycles ? horizontal : horizontalWithoutCycles)(element, info.selector, focused, -1);
  6210. const moveRight$2 = (element, focused, info) => (info.cycles ? horizontal : horizontalWithoutCycles)(element, info.selector, focused, +1);
  6211. const doMove$1 = movement => (component, simulatedEvent, flowConfig, flowState) => movement(component, simulatedEvent, flowConfig, flowState).bind(() => flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true));
  6212. const doEscape = (component, simulatedEvent, flowConfig) => flowConfig.onEscape(component, simulatedEvent);
  6213. const getKeydownRules$3 = (_component, _se, flowConfig, _flowState) => {
  6214. const westMovers = [...flowConfig.allowHorizontal ? LEFT : []].concat(flowConfig.allowVertical ? UP : []);
  6215. const eastMovers = [...flowConfig.allowHorizontal ? RIGHT : []].concat(flowConfig.allowVertical ? DOWN : []);
  6216. return [
  6217. rule(inSet(westMovers), doMove$1(west$1(moveLeft$2, moveRight$2))),
  6218. rule(inSet(eastMovers), doMove$1(east$1(moveLeft$2, moveRight$2))),
  6219. rule(inSet(ENTER), execute$2),
  6220. rule(inSet(SPACE), execute$2)
  6221. ];
  6222. };
  6223. const getKeyupRules$3 = constant$1([
  6224. rule(inSet(SPACE), stopEventForFirefox),
  6225. rule(inSet(ESCAPE), doEscape)
  6226. ]);
  6227. var FlowType = typical(schema$t, NoState.init, getKeydownRules$3, getKeyupRules$3, () => Optional.some(focusIn$2));
  6228. const toCell = (matrix, rowIndex, columnIndex) => Optional.from(matrix[rowIndex]).bind(row => Optional.from(row[columnIndex]).map(cell => ({
  6229. rowIndex,
  6230. columnIndex,
  6231. cell
  6232. })));
  6233. const cycleHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
  6234. const row = matrix[rowIndex];
  6235. const colsInRow = row.length;
  6236. const newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1);
  6237. return toCell(matrix, rowIndex, newColIndex);
  6238. };
  6239. const cycleVertical = (matrix, colIndex, startRow, deltaRow) => {
  6240. const nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix.length - 1);
  6241. const colsInNextRow = matrix[nextRowIndex].length;
  6242. const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
  6243. return toCell(matrix, nextRowIndex, nextColIndex);
  6244. };
  6245. const moveHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
  6246. const row = matrix[rowIndex];
  6247. const colsInRow = row.length;
  6248. const newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1);
  6249. return toCell(matrix, rowIndex, newColIndex);
  6250. };
  6251. const moveVertical = (matrix, colIndex, startRow, deltaRow) => {
  6252. const nextRowIndex = clamp(startRow + deltaRow, 0, matrix.length - 1);
  6253. const colsInNextRow = matrix[nextRowIndex].length;
  6254. const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
  6255. return toCell(matrix, nextRowIndex, nextColIndex);
  6256. };
  6257. const cycleRight = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, +1);
  6258. const cycleLeft = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, -1);
  6259. const cycleUp = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, -1);
  6260. const cycleDown = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, +1);
  6261. const moveLeft$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, -1);
  6262. const moveRight$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, +1);
  6263. const moveUp$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, -1);
  6264. const moveDown$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, +1);
  6265. const schema$s = [
  6266. requiredObjOf('selectors', [
  6267. required$1('row'),
  6268. required$1('cell')
  6269. ]),
  6270. defaulted('cycles', true),
  6271. defaulted('previousSelector', Optional.none),
  6272. defaulted('execute', defaultExecute)
  6273. ];
  6274. const focusIn$1 = (component, matrixConfig, _state) => {
  6275. const focused = matrixConfig.previousSelector(component).orThunk(() => {
  6276. const selectors = matrixConfig.selectors;
  6277. return descendant(component.element, selectors.cell);
  6278. });
  6279. focused.each(cell => {
  6280. matrixConfig.focusManager.set(component, cell);
  6281. });
  6282. };
  6283. const execute$1 = (component, simulatedEvent, matrixConfig) => search(component.element).bind(focused => matrixConfig.execute(component, simulatedEvent, focused));
  6284. const toMatrix = (rows, matrixConfig) => map$2(rows, row => descendants(row, matrixConfig.selectors.cell));
  6285. const doMove = (ifCycle, ifMove) => (element, focused, matrixConfig) => {
  6286. const move = matrixConfig.cycles ? ifCycle : ifMove;
  6287. return closest$1(focused, matrixConfig.selectors.row).bind(inRow => {
  6288. const cellsInRow = descendants(inRow, matrixConfig.selectors.cell);
  6289. return findIndex(cellsInRow, focused).bind(colIndex => {
  6290. const allRows = descendants(element, matrixConfig.selectors.row);
  6291. return findIndex(allRows, inRow).bind(rowIndex => {
  6292. const matrix = toMatrix(allRows, matrixConfig);
  6293. return move(matrix, rowIndex, colIndex).map(next => next.cell);
  6294. });
  6295. });
  6296. });
  6297. };
  6298. const moveLeft = doMove(cycleLeft, moveLeft$1);
  6299. const moveRight = doMove(cycleRight, moveRight$1);
  6300. const moveNorth = doMove(cycleUp, moveUp$1);
  6301. const moveSouth = doMove(cycleDown, moveDown$1);
  6302. const getKeydownRules$2 = constant$1([
  6303. rule(inSet(LEFT), west$1(moveLeft, moveRight)),
  6304. rule(inSet(RIGHT), east$1(moveLeft, moveRight)),
  6305. rule(inSet(UP), north$1(moveNorth)),
  6306. rule(inSet(DOWN), south$1(moveSouth)),
  6307. rule(inSet(SPACE.concat(ENTER)), execute$1)
  6308. ]);
  6309. const getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  6310. var MatrixType = typical(schema$s, NoState.init, getKeydownRules$2, getKeyupRules$2, () => Optional.some(focusIn$1));
  6311. const schema$r = [
  6312. required$1('selector'),
  6313. defaulted('execute', defaultExecute),
  6314. defaulted('moveOnTab', false)
  6315. ];
  6316. const execute = (component, simulatedEvent, menuConfig) => menuConfig.focusManager.get(component).bind(focused => menuConfig.execute(component, simulatedEvent, focused));
  6317. const focusIn = (component, menuConfig, _state) => {
  6318. descendant(component.element, menuConfig.selector).each(first => {
  6319. menuConfig.focusManager.set(component, first);
  6320. });
  6321. };
  6322. const moveUp = (element, focused, info) => horizontal(element, info.selector, focused, -1);
  6323. const moveDown = (element, focused, info) => horizontal(element, info.selector, focused, +1);
  6324. const fireShiftTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  6325. const fireTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  6326. const getKeydownRules$1 = constant$1([
  6327. rule(inSet(UP), move$1(moveUp)),
  6328. rule(inSet(DOWN), move$1(moveDown)),
  6329. rule(and([
  6330. isShift$1,
  6331. inSet(TAB)
  6332. ]), fireShiftTab),
  6333. rule(and([
  6334. isNotShift,
  6335. inSet(TAB)
  6336. ]), fireTab),
  6337. rule(inSet(ENTER), execute),
  6338. rule(inSet(SPACE), execute)
  6339. ]);
  6340. const getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  6341. var MenuType = typical(schema$r, NoState.init, getKeydownRules$1, getKeyupRules$1, () => Optional.some(focusIn));
  6342. const schema$q = [
  6343. onKeyboardHandler('onSpace'),
  6344. onKeyboardHandler('onEnter'),
  6345. onKeyboardHandler('onShiftEnter'),
  6346. onKeyboardHandler('onLeft'),
  6347. onKeyboardHandler('onRight'),
  6348. onKeyboardHandler('onTab'),
  6349. onKeyboardHandler('onShiftTab'),
  6350. onKeyboardHandler('onUp'),
  6351. onKeyboardHandler('onDown'),
  6352. onKeyboardHandler('onEscape'),
  6353. defaulted('stopSpaceKeyup', false),
  6354. option$3('focusIn')
  6355. ];
  6356. const getKeydownRules = (component, simulatedEvent, specialInfo) => [
  6357. rule(inSet(SPACE), specialInfo.onSpace),
  6358. rule(and([
  6359. isNotShift,
  6360. inSet(ENTER)
  6361. ]), specialInfo.onEnter),
  6362. rule(and([
  6363. isShift$1,
  6364. inSet(ENTER)
  6365. ]), specialInfo.onShiftEnter),
  6366. rule(and([
  6367. isShift$1,
  6368. inSet(TAB)
  6369. ]), specialInfo.onShiftTab),
  6370. rule(and([
  6371. isNotShift,
  6372. inSet(TAB)
  6373. ]), specialInfo.onTab),
  6374. rule(inSet(UP), specialInfo.onUp),
  6375. rule(inSet(DOWN), specialInfo.onDown),
  6376. rule(inSet(LEFT), specialInfo.onLeft),
  6377. rule(inSet(RIGHT), specialInfo.onRight),
  6378. rule(inSet(SPACE), specialInfo.onSpace)
  6379. ];
  6380. const getKeyupRules = (component, simulatedEvent, specialInfo) => [
  6381. ...specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : [],
  6382. rule(inSet(ESCAPE), specialInfo.onEscape)
  6383. ];
  6384. var SpecialType = typical(schema$q, NoState.init, getKeydownRules, getKeyupRules, specialInfo => specialInfo.focusIn);
  6385. const acyclic = AcyclicType.schema();
  6386. const cyclic = CyclicType.schema();
  6387. const flow = FlowType.schema();
  6388. const flatgrid = FlatgridType.schema();
  6389. const matrix = MatrixType.schema();
  6390. const execution = ExecutionType.schema();
  6391. const menu = MenuType.schema();
  6392. const special = SpecialType.schema();
  6393. var KeyboardBranches = /*#__PURE__*/Object.freeze({
  6394. __proto__: null,
  6395. acyclic: acyclic,
  6396. cyclic: cyclic,
  6397. flow: flow,
  6398. flatgrid: flatgrid,
  6399. matrix: matrix,
  6400. execution: execution,
  6401. menu: menu,
  6402. special: special
  6403. });
  6404. const isFlatgridState = keyState => hasNonNullableKey(keyState, 'setGridSize');
  6405. const Keying = createModes({
  6406. branchKey: 'mode',
  6407. branches: KeyboardBranches,
  6408. name: 'keying',
  6409. active: {
  6410. events: (keyingConfig, keyingState) => {
  6411. const handler = keyingConfig.handler;
  6412. return handler.toEvents(keyingConfig, keyingState);
  6413. }
  6414. },
  6415. apis: {
  6416. focusIn: (component, keyConfig, keyState) => {
  6417. keyConfig.sendFocusIn(keyConfig).fold(() => {
  6418. component.getSystem().triggerFocus(component.element, component.element);
  6419. }, sendFocusIn => {
  6420. sendFocusIn(component, keyConfig, keyState);
  6421. });
  6422. },
  6423. setGridSize: (component, keyConfig, keyState, numRows, numColumns) => {
  6424. if (!isFlatgridState(keyState)) {
  6425. console.error('Layout does not support setGridSize');
  6426. } else {
  6427. keyState.setGridSize(numRows, numColumns);
  6428. }
  6429. }
  6430. },
  6431. state: KeyingState
  6432. });
  6433. const withoutReuse = (parent, data) => {
  6434. preserve$1(() => {
  6435. replaceChildren(parent, data, () => map$2(data, parent.getSystem().build));
  6436. }, parent.element);
  6437. };
  6438. const withReuse = (parent, data) => {
  6439. preserve$1(() => {
  6440. virtualReplaceChildren(parent, data, () => {
  6441. return patchSpecChildren(parent.element, data, parent.getSystem().buildOrPatch);
  6442. });
  6443. }, parent.element);
  6444. };
  6445. const virtualReplace = (component, replacee, replaceeIndex, childSpec) => {
  6446. virtualDetach(replacee);
  6447. const child = patchSpecChild(component.element, replaceeIndex, childSpec, component.getSystem().buildOrPatch);
  6448. virtualAttach(component, child);
  6449. component.syncComponents();
  6450. };
  6451. const insert = (component, insertion, childSpec) => {
  6452. const child = component.getSystem().build(childSpec);
  6453. attachWith(component, child, insertion);
  6454. };
  6455. const replace = (component, replacee, replaceeIndex, childSpec) => {
  6456. detach(replacee);
  6457. insert(component, (p, c) => appendAt(p, c, replaceeIndex), childSpec);
  6458. };
  6459. const set$3 = (component, replaceConfig, replaceState, data) => {
  6460. const replacer = replaceConfig.reuseDom ? withReuse : withoutReuse;
  6461. return replacer(component, data);
  6462. };
  6463. const append = (component, replaceConfig, replaceState, appendee) => {
  6464. insert(component, append$2, appendee);
  6465. };
  6466. const prepend = (component, replaceConfig, replaceState, prependee) => {
  6467. insert(component, prepend$1, prependee);
  6468. };
  6469. const remove = (component, replaceConfig, replaceState, removee) => {
  6470. const children = contents(component);
  6471. const foundChild = find$5(children, child => eq(removee.element, child.element));
  6472. foundChild.each(detach);
  6473. };
  6474. const contents = (component, _replaceConfig) => component.components();
  6475. const replaceAt = (component, replaceConfig, replaceState, replaceeIndex, replacer) => {
  6476. const children = contents(component);
  6477. return Optional.from(children[replaceeIndex]).map(replacee => {
  6478. replacer.fold(() => detach(replacee), r => {
  6479. const replacer = replaceConfig.reuseDom ? virtualReplace : replace;
  6480. replacer(component, replacee, replaceeIndex, r);
  6481. });
  6482. return replacee;
  6483. });
  6484. };
  6485. const replaceBy = (component, replaceConfig, replaceState, replaceePred, replacer) => {
  6486. const children = contents(component);
  6487. return findIndex$1(children, replaceePred).bind(replaceeIndex => replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer));
  6488. };
  6489. var ReplaceApis = /*#__PURE__*/Object.freeze({
  6490. __proto__: null,
  6491. append: append,
  6492. prepend: prepend,
  6493. remove: remove,
  6494. replaceAt: replaceAt,
  6495. replaceBy: replaceBy,
  6496. set: set$3,
  6497. contents: contents
  6498. });
  6499. const Replacing = create$4({
  6500. fields: [defaultedBoolean('reuseDom', true)],
  6501. name: 'replacing',
  6502. apis: ReplaceApis
  6503. });
  6504. const events$d = (name, eventHandlers) => {
  6505. const events = derive$2(eventHandlers);
  6506. return create$4({
  6507. fields: [required$1('enabled')],
  6508. name,
  6509. active: { events: constant$1(events) }
  6510. });
  6511. };
  6512. const config = (name, eventHandlers) => {
  6513. const me = events$d(name, eventHandlers);
  6514. return {
  6515. key: name,
  6516. value: {
  6517. config: {},
  6518. me,
  6519. configAsRaw: constant$1({}),
  6520. initialConfig: {},
  6521. state: NoState
  6522. }
  6523. };
  6524. };
  6525. const focus$2 = (component, focusConfig) => {
  6526. if (!focusConfig.ignore) {
  6527. focus$3(component.element);
  6528. focusConfig.onFocus(component);
  6529. }
  6530. };
  6531. const blur = (component, focusConfig) => {
  6532. if (!focusConfig.ignore) {
  6533. blur$1(component.element);
  6534. }
  6535. };
  6536. const isFocused = component => hasFocus(component.element);
  6537. var FocusApis = /*#__PURE__*/Object.freeze({
  6538. __proto__: null,
  6539. focus: focus$2,
  6540. blur: blur,
  6541. isFocused: isFocused
  6542. });
  6543. const exhibit$4 = (base, focusConfig) => {
  6544. const mod = focusConfig.ignore ? {} : { attributes: { tabindex: '-1' } };
  6545. return nu$7(mod);
  6546. };
  6547. const events$c = focusConfig => derive$2([run$1(focus$4(), (component, simulatedEvent) => {
  6548. focus$2(component, focusConfig);
  6549. simulatedEvent.stop();
  6550. })].concat(focusConfig.stopMousedown ? [run$1(mousedown(), (_, simulatedEvent) => {
  6551. simulatedEvent.event.prevent();
  6552. })] : []));
  6553. var ActiveFocus = /*#__PURE__*/Object.freeze({
  6554. __proto__: null,
  6555. exhibit: exhibit$4,
  6556. events: events$c
  6557. });
  6558. var FocusSchema = [
  6559. onHandler('onFocus'),
  6560. defaulted('stopMousedown', false),
  6561. defaulted('ignore', false)
  6562. ];
  6563. const Focusing = create$4({
  6564. fields: FocusSchema,
  6565. name: 'focusing',
  6566. active: ActiveFocus,
  6567. apis: FocusApis
  6568. });
  6569. const SetupBehaviourCellState = initialState => {
  6570. const init = () => {
  6571. const cell = Cell(initialState);
  6572. const get = () => cell.get();
  6573. const set = newState => cell.set(newState);
  6574. const clear = () => cell.set(initialState);
  6575. const readState = () => cell.get();
  6576. return {
  6577. get,
  6578. set,
  6579. clear,
  6580. readState
  6581. };
  6582. };
  6583. return { init };
  6584. };
  6585. const updateAriaState = (component, toggleConfig, toggleState) => {
  6586. const ariaInfo = toggleConfig.aria;
  6587. ariaInfo.update(component, ariaInfo, toggleState.get());
  6588. };
  6589. const updateClass = (component, toggleConfig, toggleState) => {
  6590. toggleConfig.toggleClass.each(toggleClass => {
  6591. if (toggleState.get()) {
  6592. add$2(component.element, toggleClass);
  6593. } else {
  6594. remove$2(component.element, toggleClass);
  6595. }
  6596. });
  6597. };
  6598. const set$2 = (component, toggleConfig, toggleState, state) => {
  6599. const initialState = toggleState.get();
  6600. toggleState.set(state);
  6601. updateClass(component, toggleConfig, toggleState);
  6602. updateAriaState(component, toggleConfig, toggleState);
  6603. if (initialState !== state) {
  6604. toggleConfig.onToggled(component, state);
  6605. }
  6606. };
  6607. const toggle$2 = (component, toggleConfig, toggleState) => {
  6608. set$2(component, toggleConfig, toggleState, !toggleState.get());
  6609. };
  6610. const on = (component, toggleConfig, toggleState) => {
  6611. set$2(component, toggleConfig, toggleState, true);
  6612. };
  6613. const off = (component, toggleConfig, toggleState) => {
  6614. set$2(component, toggleConfig, toggleState, false);
  6615. };
  6616. const isOn = (component, toggleConfig, toggleState) => toggleState.get();
  6617. const onLoad = (component, toggleConfig, toggleState) => {
  6618. set$2(component, toggleConfig, toggleState, toggleConfig.selected);
  6619. };
  6620. var ToggleApis = /*#__PURE__*/Object.freeze({
  6621. __proto__: null,
  6622. onLoad: onLoad,
  6623. toggle: toggle$2,
  6624. isOn: isOn,
  6625. on: on,
  6626. off: off,
  6627. set: set$2
  6628. });
  6629. const exhibit$3 = () => nu$7({});
  6630. const events$b = (toggleConfig, toggleState) => {
  6631. const execute = executeEvent(toggleConfig, toggleState, toggle$2);
  6632. const load = loadEvent(toggleConfig, toggleState, onLoad);
  6633. return derive$2(flatten([
  6634. toggleConfig.toggleOnExecute ? [execute] : [],
  6635. [load]
  6636. ]));
  6637. };
  6638. var ActiveToggle = /*#__PURE__*/Object.freeze({
  6639. __proto__: null,
  6640. exhibit: exhibit$3,
  6641. events: events$b
  6642. });
  6643. const updatePressed = (component, ariaInfo, status) => {
  6644. set$9(component.element, 'aria-pressed', status);
  6645. if (ariaInfo.syncWithExpanded) {
  6646. updateExpanded(component, ariaInfo, status);
  6647. }
  6648. };
  6649. const updateSelected = (component, ariaInfo, status) => {
  6650. set$9(component.element, 'aria-selected', status);
  6651. };
  6652. const updateChecked = (component, ariaInfo, status) => {
  6653. set$9(component.element, 'aria-checked', status);
  6654. };
  6655. const updateExpanded = (component, ariaInfo, status) => {
  6656. set$9(component.element, 'aria-expanded', status);
  6657. };
  6658. var ToggleSchema = [
  6659. defaulted('selected', false),
  6660. option$3('toggleClass'),
  6661. defaulted('toggleOnExecute', true),
  6662. onHandler('onToggled'),
  6663. defaultedOf('aria', { mode: 'none' }, choose$1('mode', {
  6664. pressed: [
  6665. defaulted('syncWithExpanded', false),
  6666. output$1('update', updatePressed)
  6667. ],
  6668. checked: [output$1('update', updateChecked)],
  6669. expanded: [output$1('update', updateExpanded)],
  6670. selected: [output$1('update', updateSelected)],
  6671. none: [output$1('update', noop)]
  6672. }))
  6673. ];
  6674. const Toggling = create$4({
  6675. fields: ToggleSchema,
  6676. name: 'toggling',
  6677. active: ActiveToggle,
  6678. apis: ToggleApis,
  6679. state: SetupBehaviourCellState(false)
  6680. });
  6681. const pointerEvents = () => {
  6682. const onClick = (component, simulatedEvent) => {
  6683. simulatedEvent.stop();
  6684. emitExecute(component);
  6685. };
  6686. return [
  6687. run$1(click(), onClick),
  6688. run$1(tap(), onClick),
  6689. cutter(touchstart()),
  6690. cutter(mousedown())
  6691. ];
  6692. };
  6693. const events$a = optAction => {
  6694. const executeHandler = action => runOnExecute$1((component, simulatedEvent) => {
  6695. action(component);
  6696. simulatedEvent.stop();
  6697. });
  6698. return derive$2(flatten([
  6699. optAction.map(executeHandler).toArray(),
  6700. pointerEvents()
  6701. ]));
  6702. };
  6703. const hoverEvent = 'alloy.item-hover';
  6704. const focusEvent = 'alloy.item-focus';
  6705. const toggledEvent = 'alloy.item-toggled';
  6706. const onHover = item => {
  6707. if (search(item.element).isNone() || Focusing.isFocused(item)) {
  6708. if (!Focusing.isFocused(item)) {
  6709. Focusing.focus(item);
  6710. }
  6711. emitWith(item, hoverEvent, { item });
  6712. }
  6713. };
  6714. const onFocus$1 = item => {
  6715. emitWith(item, focusEvent, { item });
  6716. };
  6717. const onToggled = (item, state) => {
  6718. emitWith(item, toggledEvent, {
  6719. item,
  6720. state
  6721. });
  6722. };
  6723. const hover = constant$1(hoverEvent);
  6724. const focus$1 = constant$1(focusEvent);
  6725. const toggled = constant$1(toggledEvent);
  6726. const getItemRole = detail => detail.toggling.map(toggling => toggling.exclusive ? 'menuitemradio' : 'menuitemcheckbox').getOr('menuitem');
  6727. const getTogglingSpec = tConfig => ({
  6728. aria: { mode: 'checked' },
  6729. ...filter$1(tConfig, (_value, name) => name !== 'exclusive'),
  6730. onToggled: (component, state) => {
  6731. if (isFunction(tConfig.onToggled)) {
  6732. tConfig.onToggled(component, state);
  6733. }
  6734. onToggled(component, state);
  6735. }
  6736. });
  6737. const builder$2 = detail => ({
  6738. dom: detail.dom,
  6739. domModification: {
  6740. ...detail.domModification,
  6741. attributes: {
  6742. 'role': getItemRole(detail),
  6743. ...detail.domModification.attributes,
  6744. 'aria-haspopup': detail.hasSubmenu,
  6745. ...detail.hasSubmenu ? { 'aria-expanded': false } : {}
  6746. }
  6747. },
  6748. behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
  6749. detail.toggling.fold(Toggling.revoke, tConfig => Toggling.config(getTogglingSpec(tConfig))),
  6750. Focusing.config({
  6751. ignore: detail.ignoreFocus,
  6752. stopMousedown: detail.ignoreFocus,
  6753. onFocus: component => {
  6754. onFocus$1(component);
  6755. }
  6756. }),
  6757. Keying.config({ mode: 'execution' }),
  6758. Representing.config({
  6759. store: {
  6760. mode: 'memory',
  6761. initialValue: detail.data
  6762. }
  6763. }),
  6764. config('item-type-events', [
  6765. ...pointerEvents(),
  6766. run$1(mouseover(), onHover),
  6767. run$1(focusItem(), Focusing.focus)
  6768. ])
  6769. ]),
  6770. components: detail.components,
  6771. eventOrder: detail.eventOrder
  6772. });
  6773. const schema$p = [
  6774. required$1('data'),
  6775. required$1('components'),
  6776. required$1('dom'),
  6777. defaulted('hasSubmenu', false),
  6778. option$3('toggling'),
  6779. SketchBehaviours.field('itemBehaviours', [
  6780. Toggling,
  6781. Focusing,
  6782. Keying,
  6783. Representing
  6784. ]),
  6785. defaulted('ignoreFocus', false),
  6786. defaulted('domModification', {}),
  6787. output$1('builder', builder$2),
  6788. defaulted('eventOrder', {})
  6789. ];
  6790. const builder$1 = detail => ({
  6791. dom: detail.dom,
  6792. components: detail.components,
  6793. events: derive$2([stopper(focusItem())])
  6794. });
  6795. const schema$o = [
  6796. required$1('dom'),
  6797. required$1('components'),
  6798. output$1('builder', builder$1)
  6799. ];
  6800. const owner$2 = constant$1('item-widget');
  6801. const parts$h = constant$1([required({
  6802. name: 'widget',
  6803. overrides: detail => {
  6804. return {
  6805. behaviours: derive$1([Representing.config({
  6806. store: {
  6807. mode: 'manual',
  6808. getValue: _component => {
  6809. return detail.data;
  6810. },
  6811. setValue: noop
  6812. }
  6813. })])
  6814. };
  6815. }
  6816. })]);
  6817. const builder = detail => {
  6818. const subs = substitutes(owner$2(), detail, parts$h());
  6819. const components = components$1(owner$2(), detail, subs.internals());
  6820. const focusWidget = component => getPart(component, detail, 'widget').map(widget => {
  6821. Keying.focusIn(widget);
  6822. return widget;
  6823. });
  6824. const onHorizontalArrow = (component, simulatedEvent) => inside(simulatedEvent.event.target) ? Optional.none() : (() => {
  6825. if (detail.autofocus) {
  6826. simulatedEvent.setSource(component.element);
  6827. return Optional.none();
  6828. } else {
  6829. return Optional.none();
  6830. }
  6831. })();
  6832. return {
  6833. dom: detail.dom,
  6834. components,
  6835. domModification: detail.domModification,
  6836. events: derive$2([
  6837. runOnExecute$1((component, simulatedEvent) => {
  6838. focusWidget(component).each(_widget => {
  6839. simulatedEvent.stop();
  6840. });
  6841. }),
  6842. run$1(mouseover(), onHover),
  6843. run$1(focusItem(), (component, _simulatedEvent) => {
  6844. if (detail.autofocus) {
  6845. focusWidget(component);
  6846. } else {
  6847. Focusing.focus(component);
  6848. }
  6849. })
  6850. ]),
  6851. behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
  6852. Representing.config({
  6853. store: {
  6854. mode: 'memory',
  6855. initialValue: detail.data
  6856. }
  6857. }),
  6858. Focusing.config({
  6859. ignore: detail.ignoreFocus,
  6860. onFocus: component => {
  6861. onFocus$1(component);
  6862. }
  6863. }),
  6864. Keying.config({
  6865. mode: 'special',
  6866. focusIn: detail.autofocus ? component => {
  6867. focusWidget(component);
  6868. } : revoke(),
  6869. onLeft: onHorizontalArrow,
  6870. onRight: onHorizontalArrow,
  6871. onEscape: (component, simulatedEvent) => {
  6872. if (!Focusing.isFocused(component) && !detail.autofocus) {
  6873. Focusing.focus(component);
  6874. return Optional.some(true);
  6875. } else if (detail.autofocus) {
  6876. simulatedEvent.setSource(component.element);
  6877. return Optional.none();
  6878. } else {
  6879. return Optional.none();
  6880. }
  6881. }
  6882. })
  6883. ])
  6884. };
  6885. };
  6886. const schema$n = [
  6887. required$1('uid'),
  6888. required$1('data'),
  6889. required$1('components'),
  6890. required$1('dom'),
  6891. defaulted('autofocus', false),
  6892. defaulted('ignoreFocus', false),
  6893. SketchBehaviours.field('widgetBehaviours', [
  6894. Representing,
  6895. Focusing,
  6896. Keying
  6897. ]),
  6898. defaulted('domModification', {}),
  6899. defaultUidsSchema(parts$h()),
  6900. output$1('builder', builder)
  6901. ];
  6902. const itemSchema$2 = choose$1('type', {
  6903. widget: schema$n,
  6904. item: schema$p,
  6905. separator: schema$o
  6906. });
  6907. const configureGrid = (detail, movementInfo) => ({
  6908. mode: 'flatgrid',
  6909. selector: '.' + detail.markers.item,
  6910. initSize: {
  6911. numColumns: movementInfo.initSize.numColumns,
  6912. numRows: movementInfo.initSize.numRows
  6913. },
  6914. focusManager: detail.focusManager
  6915. });
  6916. const configureMatrix = (detail, movementInfo) => ({
  6917. mode: 'matrix',
  6918. selectors: {
  6919. row: movementInfo.rowSelector,
  6920. cell: '.' + detail.markers.item
  6921. },
  6922. previousSelector: movementInfo.previousSelector,
  6923. focusManager: detail.focusManager
  6924. });
  6925. const configureMenu = (detail, movementInfo) => ({
  6926. mode: 'menu',
  6927. selector: '.' + detail.markers.item,
  6928. moveOnTab: movementInfo.moveOnTab,
  6929. focusManager: detail.focusManager
  6930. });
  6931. const parts$g = constant$1([group({
  6932. factory: {
  6933. sketch: spec => {
  6934. const itemInfo = asRawOrDie$1('menu.spec item', itemSchema$2, spec);
  6935. return itemInfo.builder(itemInfo);
  6936. }
  6937. },
  6938. name: 'items',
  6939. unit: 'item',
  6940. defaults: (detail, u) => {
  6941. return has$2(u, 'uid') ? u : {
  6942. ...u,
  6943. uid: generate$5('item')
  6944. };
  6945. },
  6946. overrides: (detail, u) => {
  6947. return {
  6948. type: u.type,
  6949. ignoreFocus: detail.fakeFocus,
  6950. domModification: { classes: [detail.markers.item] }
  6951. };
  6952. }
  6953. })]);
  6954. const schema$m = constant$1([
  6955. required$1('value'),
  6956. required$1('items'),
  6957. required$1('dom'),
  6958. required$1('components'),
  6959. defaulted('eventOrder', {}),
  6960. field('menuBehaviours', [
  6961. Highlighting,
  6962. Representing,
  6963. Composing,
  6964. Keying
  6965. ]),
  6966. defaultedOf('movement', {
  6967. mode: 'menu',
  6968. moveOnTab: true
  6969. }, choose$1('mode', {
  6970. grid: [
  6971. initSize(),
  6972. output$1('config', configureGrid)
  6973. ],
  6974. matrix: [
  6975. output$1('config', configureMatrix),
  6976. required$1('rowSelector'),
  6977. defaulted('previousSelector', Optional.none)
  6978. ],
  6979. menu: [
  6980. defaulted('moveOnTab', true),
  6981. output$1('config', configureMenu)
  6982. ]
  6983. })),
  6984. itemMarkers(),
  6985. defaulted('fakeFocus', false),
  6986. defaulted('focusManager', dom$2()),
  6987. onHandler('onHighlight'),
  6988. onHandler('onDehighlight')
  6989. ]);
  6990. const focus = constant$1('alloy.menu-focus');
  6991. const deselectOtherRadioItems = (menu, item) => {
  6992. const checkedRadioItems = descendants(menu.element, '[role="menuitemradio"][aria-checked="true"]');
  6993. each$1(checkedRadioItems, ele => {
  6994. if (!eq(ele, item.element)) {
  6995. menu.getSystem().getByDom(ele).each(c => {
  6996. Toggling.off(c);
  6997. });
  6998. }
  6999. });
  7000. };
  7001. const make$7 = (detail, components, _spec, _externals) => ({
  7002. uid: detail.uid,
  7003. dom: detail.dom,
  7004. markers: detail.markers,
  7005. behaviours: augment(detail.menuBehaviours, [
  7006. Highlighting.config({
  7007. highlightClass: detail.markers.selectedItem,
  7008. itemClass: detail.markers.item,
  7009. onHighlight: detail.onHighlight,
  7010. onDehighlight: detail.onDehighlight
  7011. }),
  7012. Representing.config({
  7013. store: {
  7014. mode: 'memory',
  7015. initialValue: detail.value
  7016. }
  7017. }),
  7018. Composing.config({ find: Optional.some }),
  7019. Keying.config(detail.movement.config(detail, detail.movement))
  7020. ]),
  7021. events: derive$2([
  7022. run$1(focus$1(), (menu, simulatedEvent) => {
  7023. const event = simulatedEvent.event;
  7024. menu.getSystem().getByDom(event.target).each(item => {
  7025. Highlighting.highlight(menu, item);
  7026. simulatedEvent.stop();
  7027. emitWith(menu, focus(), {
  7028. menu,
  7029. item
  7030. });
  7031. });
  7032. }),
  7033. run$1(hover(), (menu, simulatedEvent) => {
  7034. const item = simulatedEvent.event.item;
  7035. Highlighting.highlight(menu, item);
  7036. }),
  7037. run$1(toggled(), (menu, simulatedEvent) => {
  7038. const {item, state} = simulatedEvent.event;
  7039. if (state && get$f(item.element, 'role') === 'menuitemradio') {
  7040. deselectOtherRadioItems(menu, item);
  7041. }
  7042. })
  7043. ]),
  7044. components,
  7045. eventOrder: detail.eventOrder,
  7046. domModification: { attributes: { role: 'menu' } }
  7047. });
  7048. const Menu = composite({
  7049. name: 'Menu',
  7050. configFields: schema$m(),
  7051. partFields: parts$g(),
  7052. factory: make$7
  7053. });
  7054. const transpose$1 = obj => tupleMap(obj, (v, k) => ({
  7055. k: v,
  7056. v: k
  7057. }));
  7058. const trace = (items, byItem, byMenu, finish) => get$g(byMenu, finish).bind(triggerItem => get$g(items, triggerItem).bind(triggerMenu => {
  7059. const rest = trace(items, byItem, byMenu, triggerMenu);
  7060. return Optional.some([triggerMenu].concat(rest));
  7061. })).getOr([]);
  7062. const generate$2 = (menus, expansions) => {
  7063. const items = {};
  7064. each(menus, (menuItems, menu) => {
  7065. each$1(menuItems, item => {
  7066. items[item] = menu;
  7067. });
  7068. });
  7069. const byItem = expansions;
  7070. const byMenu = transpose$1(expansions);
  7071. const menuPaths = map$1(byMenu, (_triggerItem, submenu) => [submenu].concat(trace(items, byItem, byMenu, submenu)));
  7072. return map$1(items, menu => get$g(menuPaths, menu).getOr([menu]));
  7073. };
  7074. const init$c = () => {
  7075. const expansions = Cell({});
  7076. const menus = Cell({});
  7077. const paths = Cell({});
  7078. const primary = value$2();
  7079. const directory = Cell({});
  7080. const clear = () => {
  7081. expansions.set({});
  7082. menus.set({});
  7083. paths.set({});
  7084. primary.clear();
  7085. };
  7086. const isClear = () => primary.get().isNone();
  7087. const setMenuBuilt = (menuName, built) => {
  7088. menus.set({
  7089. ...menus.get(),
  7090. [menuName]: {
  7091. type: 'prepared',
  7092. menu: built
  7093. }
  7094. });
  7095. };
  7096. const setContents = (sPrimary, sMenus, sExpansions, dir) => {
  7097. primary.set(sPrimary);
  7098. expansions.set(sExpansions);
  7099. menus.set(sMenus);
  7100. directory.set(dir);
  7101. const sPaths = generate$2(dir, sExpansions);
  7102. paths.set(sPaths);
  7103. };
  7104. const getTriggeringItem = menuValue => find$4(expansions.get(), (v, _k) => v === menuValue);
  7105. const getTriggerData = (menuValue, getItemByValue, path) => getPreparedMenu(menuValue).bind(menu => getTriggeringItem(menuValue).bind(triggeringItemValue => getItemByValue(triggeringItemValue).map(triggeredItem => ({
  7106. triggeredMenu: menu,
  7107. triggeringItem: triggeredItem,
  7108. triggeringPath: path
  7109. }))));
  7110. const getTriggeringPath = (itemValue, getItemByValue) => {
  7111. const extraPath = filter$2(lookupItem(itemValue).toArray(), menuValue => getPreparedMenu(menuValue).isSome());
  7112. return get$g(paths.get(), itemValue).bind(path => {
  7113. const revPath = reverse(extraPath.concat(path));
  7114. const triggers = bind$3(revPath, (menuValue, menuIndex) => getTriggerData(menuValue, getItemByValue, revPath.slice(0, menuIndex + 1)).fold(() => is$1(primary.get(), menuValue) ? [] : [Optional.none()], data => [Optional.some(data)]));
  7115. return sequence(triggers);
  7116. });
  7117. };
  7118. const expand = itemValue => get$g(expansions.get(), itemValue).map(menu => {
  7119. const current = get$g(paths.get(), itemValue).getOr([]);
  7120. return [menu].concat(current);
  7121. });
  7122. const collapse = itemValue => get$g(paths.get(), itemValue).bind(path => path.length > 1 ? Optional.some(path.slice(1)) : Optional.none());
  7123. const refresh = itemValue => get$g(paths.get(), itemValue);
  7124. const getPreparedMenu = menuValue => lookupMenu(menuValue).bind(extractPreparedMenu);
  7125. const lookupMenu = menuValue => get$g(menus.get(), menuValue);
  7126. const lookupItem = itemValue => get$g(expansions.get(), itemValue);
  7127. const otherMenus = path => {
  7128. const menuValues = directory.get();
  7129. return difference(keys(menuValues), path);
  7130. };
  7131. const getPrimary = () => primary.get().bind(getPreparedMenu);
  7132. const getMenus = () => menus.get();
  7133. return {
  7134. setMenuBuilt,
  7135. setContents,
  7136. expand,
  7137. refresh,
  7138. collapse,
  7139. lookupMenu,
  7140. lookupItem,
  7141. otherMenus,
  7142. getPrimary,
  7143. getMenus,
  7144. clear,
  7145. isClear,
  7146. getTriggeringPath
  7147. };
  7148. };
  7149. const extractPreparedMenu = prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none();
  7150. const LayeredState = {
  7151. init: init$c,
  7152. extractPreparedMenu
  7153. };
  7154. const onMenuItemHighlightedEvent = generate$6('tiered-menu-item-highlight');
  7155. const onMenuItemDehighlightedEvent = generate$6('tiered-menu-item-dehighlight');
  7156. var HighlightOnOpen;
  7157. (function (HighlightOnOpen) {
  7158. HighlightOnOpen[HighlightOnOpen['HighlightMenuAndItem'] = 0] = 'HighlightMenuAndItem';
  7159. HighlightOnOpen[HighlightOnOpen['HighlightJustMenu'] = 1] = 'HighlightJustMenu';
  7160. HighlightOnOpen[HighlightOnOpen['HighlightNone'] = 2] = 'HighlightNone';
  7161. }(HighlightOnOpen || (HighlightOnOpen = {})));
  7162. const make$6 = (detail, _rawUiSpec) => {
  7163. const submenuParentItems = value$2();
  7164. const buildMenus = (container, primaryName, menus) => map$1(menus, (spec, name) => {
  7165. const makeSketch = () => Menu.sketch({
  7166. ...spec,
  7167. value: name,
  7168. markers: detail.markers,
  7169. fakeFocus: detail.fakeFocus,
  7170. onHighlight: (menuComp, itemComp) => {
  7171. const highlightData = {
  7172. menuComp,
  7173. itemComp
  7174. };
  7175. emitWith(menuComp, onMenuItemHighlightedEvent, highlightData);
  7176. },
  7177. onDehighlight: (menuComp, itemComp) => {
  7178. const dehighlightData = {
  7179. menuComp,
  7180. itemComp
  7181. };
  7182. emitWith(menuComp, onMenuItemDehighlightedEvent, dehighlightData);
  7183. },
  7184. focusManager: detail.fakeFocus ? highlights() : dom$2()
  7185. });
  7186. return name === primaryName ? {
  7187. type: 'prepared',
  7188. menu: container.getSystem().build(makeSketch())
  7189. } : {
  7190. type: 'notbuilt',
  7191. nbMenu: makeSketch
  7192. };
  7193. });
  7194. const layeredState = LayeredState.init();
  7195. const setup = container => {
  7196. const componentMap = buildMenus(container, detail.data.primary, detail.data.menus);
  7197. const directory = toDirectory();
  7198. layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory);
  7199. return layeredState.getPrimary();
  7200. };
  7201. const getItemValue = item => Representing.getValue(item).value;
  7202. const getItemByValue = (_container, menus, itemValue) => findMap(menus, menu => {
  7203. if (!menu.getSystem().isConnected()) {
  7204. return Optional.none();
  7205. }
  7206. const candidates = Highlighting.getCandidates(menu);
  7207. return find$5(candidates, c => getItemValue(c) === itemValue);
  7208. });
  7209. const toDirectory = _container => map$1(detail.data.menus, (data, _menuName) => bind$3(data.items, item => item.type === 'separator' ? [] : [item.data.value]));
  7210. const setActiveMenu = Highlighting.highlight;
  7211. const setActiveMenuAndItem = (container, menu) => {
  7212. setActiveMenu(container, menu);
  7213. Highlighting.getHighlighted(menu).orThunk(() => Highlighting.getFirst(menu)).each(item => {
  7214. if (detail.fakeFocus) {
  7215. Highlighting.highlight(menu, item);
  7216. } else {
  7217. dispatch(container, item.element, focusItem());
  7218. }
  7219. });
  7220. };
  7221. const getMenus = (state, menuValues) => cat(map$2(menuValues, mv => state.lookupMenu(mv).bind(prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none())));
  7222. const closeOthers = (container, state, path) => {
  7223. const others = getMenus(state, state.otherMenus(path));
  7224. each$1(others, o => {
  7225. remove$1(o.element, [detail.markers.backgroundMenu]);
  7226. if (!detail.stayInDom) {
  7227. Replacing.remove(container, o);
  7228. }
  7229. });
  7230. };
  7231. const getSubmenuParents = container => submenuParentItems.get().getOrThunk(() => {
  7232. const r = {};
  7233. const items = descendants(container.element, `.${ detail.markers.item }`);
  7234. const parentItems = filter$2(items, i => get$f(i, 'aria-haspopup') === 'true');
  7235. each$1(parentItems, i => {
  7236. container.getSystem().getByDom(i).each(itemComp => {
  7237. const key = getItemValue(itemComp);
  7238. r[key] = itemComp;
  7239. });
  7240. });
  7241. submenuParentItems.set(r);
  7242. return r;
  7243. });
  7244. const updateAriaExpansions = (container, path) => {
  7245. const parentItems = getSubmenuParents(container);
  7246. each(parentItems, (v, k) => {
  7247. const expanded = contains$2(path, k);
  7248. set$9(v.element, 'aria-expanded', expanded);
  7249. });
  7250. };
  7251. const updateMenuPath = (container, state, path) => Optional.from(path[0]).bind(latestMenuName => state.lookupMenu(latestMenuName).bind(menuPrep => {
  7252. if (menuPrep.type === 'notbuilt') {
  7253. return Optional.none();
  7254. } else {
  7255. const activeMenu = menuPrep.menu;
  7256. const rest = getMenus(state, path.slice(1));
  7257. each$1(rest, r => {
  7258. add$2(r.element, detail.markers.backgroundMenu);
  7259. });
  7260. if (!inBody(activeMenu.element)) {
  7261. Replacing.append(container, premade(activeMenu));
  7262. }
  7263. remove$1(activeMenu.element, [detail.markers.backgroundMenu]);
  7264. setActiveMenuAndItem(container, activeMenu);
  7265. closeOthers(container, state, path);
  7266. return Optional.some(activeMenu);
  7267. }
  7268. }));
  7269. let ExpandHighlightDecision;
  7270. (function (ExpandHighlightDecision) {
  7271. ExpandHighlightDecision[ExpandHighlightDecision['HighlightSubmenu'] = 0] = 'HighlightSubmenu';
  7272. ExpandHighlightDecision[ExpandHighlightDecision['HighlightParent'] = 1] = 'HighlightParent';
  7273. }(ExpandHighlightDecision || (ExpandHighlightDecision = {})));
  7274. const buildIfRequired = (container, menuName, menuPrep) => {
  7275. if (menuPrep.type === 'notbuilt') {
  7276. const menu = container.getSystem().build(menuPrep.nbMenu());
  7277. layeredState.setMenuBuilt(menuName, menu);
  7278. return menu;
  7279. } else {
  7280. return menuPrep.menu;
  7281. }
  7282. };
  7283. const expandRight = (container, item, decision = ExpandHighlightDecision.HighlightSubmenu) => {
  7284. if (item.hasConfigured(Disabling) && Disabling.isDisabled(item)) {
  7285. return Optional.some(item);
  7286. } else {
  7287. const value = getItemValue(item);
  7288. return layeredState.expand(value).bind(path => {
  7289. updateAriaExpansions(container, path);
  7290. return Optional.from(path[0]).bind(menuName => layeredState.lookupMenu(menuName).bind(activeMenuPrep => {
  7291. const activeMenu = buildIfRequired(container, menuName, activeMenuPrep);
  7292. if (!inBody(activeMenu.element)) {
  7293. Replacing.append(container, premade(activeMenu));
  7294. }
  7295. detail.onOpenSubmenu(container, item, activeMenu, reverse(path));
  7296. if (decision === ExpandHighlightDecision.HighlightSubmenu) {
  7297. Highlighting.highlightFirst(activeMenu);
  7298. return updateMenuPath(container, layeredState, path);
  7299. } else {
  7300. Highlighting.dehighlightAll(activeMenu);
  7301. return Optional.some(item);
  7302. }
  7303. }));
  7304. });
  7305. }
  7306. };
  7307. const collapseLeft = (container, item) => {
  7308. const value = getItemValue(item);
  7309. return layeredState.collapse(value).bind(path => {
  7310. updateAriaExpansions(container, path);
  7311. return updateMenuPath(container, layeredState, path).map(activeMenu => {
  7312. detail.onCollapseMenu(container, item, activeMenu);
  7313. return activeMenu;
  7314. });
  7315. });
  7316. };
  7317. const updateView = (container, item) => {
  7318. const value = getItemValue(item);
  7319. return layeredState.refresh(value).bind(path => {
  7320. updateAriaExpansions(container, path);
  7321. return updateMenuPath(container, layeredState, path);
  7322. });
  7323. };
  7324. const onRight = (container, item) => inside(item.element) ? Optional.none() : expandRight(container, item, ExpandHighlightDecision.HighlightSubmenu);
  7325. const onLeft = (container, item) => inside(item.element) ? Optional.none() : collapseLeft(container, item);
  7326. const onEscape = (container, item) => collapseLeft(container, item).orThunk(() => detail.onEscape(container, item).map(() => container));
  7327. const keyOnItem = f => (container, simulatedEvent) => {
  7328. return closest$1(simulatedEvent.getSource(), `.${ detail.markers.item }`).bind(target => container.getSystem().getByDom(target).toOptional().bind(item => f(container, item).map(always)));
  7329. };
  7330. const events = derive$2([
  7331. run$1(focus(), (tmenu, simulatedEvent) => {
  7332. const item = simulatedEvent.event.item;
  7333. layeredState.lookupItem(getItemValue(item)).each(() => {
  7334. const menu = simulatedEvent.event.menu;
  7335. Highlighting.highlight(tmenu, menu);
  7336. const value = getItemValue(simulatedEvent.event.item);
  7337. layeredState.refresh(value).each(path => closeOthers(tmenu, layeredState, path));
  7338. });
  7339. }),
  7340. runOnExecute$1((component, simulatedEvent) => {
  7341. const target = simulatedEvent.event.target;
  7342. component.getSystem().getByDom(target).each(item => {
  7343. const itemValue = getItemValue(item);
  7344. if (itemValue.indexOf('collapse-item') === 0) {
  7345. collapseLeft(component, item);
  7346. }
  7347. expandRight(component, item, ExpandHighlightDecision.HighlightSubmenu).fold(() => {
  7348. detail.onExecute(component, item);
  7349. }, noop);
  7350. });
  7351. }),
  7352. runOnAttached((container, _simulatedEvent) => {
  7353. setup(container).each(primary => {
  7354. Replacing.append(container, premade(primary));
  7355. detail.onOpenMenu(container, primary);
  7356. if (detail.highlightOnOpen === HighlightOnOpen.HighlightMenuAndItem) {
  7357. setActiveMenuAndItem(container, primary);
  7358. } else if (detail.highlightOnOpen === HighlightOnOpen.HighlightJustMenu) {
  7359. setActiveMenu(container, primary);
  7360. }
  7361. });
  7362. }),
  7363. run$1(onMenuItemHighlightedEvent, (tmenuComp, se) => {
  7364. detail.onHighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
  7365. }),
  7366. run$1(onMenuItemDehighlightedEvent, (tmenuComp, se) => {
  7367. detail.onDehighlightItem(tmenuComp, se.event.menuComp, se.event.itemComp);
  7368. }),
  7369. ...detail.navigateOnHover ? [run$1(hover(), (tmenu, simulatedEvent) => {
  7370. const item = simulatedEvent.event.item;
  7371. updateView(tmenu, item);
  7372. expandRight(tmenu, item, ExpandHighlightDecision.HighlightParent);
  7373. detail.onHover(tmenu, item);
  7374. })] : []
  7375. ]);
  7376. const getActiveItem = container => Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted);
  7377. const collapseMenuApi = container => {
  7378. getActiveItem(container).each(currentItem => {
  7379. collapseLeft(container, currentItem);
  7380. });
  7381. };
  7382. const highlightPrimary = container => {
  7383. layeredState.getPrimary().each(primary => {
  7384. setActiveMenuAndItem(container, primary);
  7385. });
  7386. };
  7387. const extractMenuFromContainer = container => Optional.from(container.components()[0]).filter(comp => get$f(comp.element, 'role') === 'menu');
  7388. const repositionMenus = container => {
  7389. const maybeActivePrimary = layeredState.getPrimary().bind(primary => getActiveItem(container).bind(currentItem => {
  7390. const itemValue = getItemValue(currentItem);
  7391. const allMenus = values(layeredState.getMenus());
  7392. const preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu));
  7393. return layeredState.getTriggeringPath(itemValue, v => getItemByValue(container, preparedMenus, v));
  7394. }).map(triggeringPath => ({
  7395. primary,
  7396. triggeringPath
  7397. })));
  7398. maybeActivePrimary.fold(() => {
  7399. extractMenuFromContainer(container).each(primaryMenu => {
  7400. detail.onRepositionMenu(container, primaryMenu, []);
  7401. });
  7402. }, ({primary, triggeringPath}) => {
  7403. detail.onRepositionMenu(container, primary, triggeringPath);
  7404. });
  7405. };
  7406. const apis = {
  7407. collapseMenu: collapseMenuApi,
  7408. highlightPrimary,
  7409. repositionMenus
  7410. };
  7411. return {
  7412. uid: detail.uid,
  7413. dom: detail.dom,
  7414. markers: detail.markers,
  7415. behaviours: augment(detail.tmenuBehaviours, [
  7416. Keying.config({
  7417. mode: 'special',
  7418. onRight: keyOnItem(onRight),
  7419. onLeft: keyOnItem(onLeft),
  7420. onEscape: keyOnItem(onEscape),
  7421. focusIn: (container, _keyInfo) => {
  7422. layeredState.getPrimary().each(primary => {
  7423. dispatch(container, primary.element, focusItem());
  7424. });
  7425. }
  7426. }),
  7427. Highlighting.config({
  7428. highlightClass: detail.markers.selectedMenu,
  7429. itemClass: detail.markers.menu
  7430. }),
  7431. Composing.config({
  7432. find: container => {
  7433. return Highlighting.getHighlighted(container);
  7434. }
  7435. }),
  7436. Replacing.config({})
  7437. ]),
  7438. eventOrder: detail.eventOrder,
  7439. apis,
  7440. events
  7441. };
  7442. };
  7443. const collapseItem$1 = constant$1('collapse-item');
  7444. const tieredData = (primary, menus, expansions) => ({
  7445. primary,
  7446. menus,
  7447. expansions
  7448. });
  7449. const singleData = (name, menu) => ({
  7450. primary: name,
  7451. menus: wrap$1(name, menu),
  7452. expansions: {}
  7453. });
  7454. const collapseItem = text => ({
  7455. value: generate$6(collapseItem$1()),
  7456. meta: { text }
  7457. });
  7458. const tieredMenu = single({
  7459. name: 'TieredMenu',
  7460. configFields: [
  7461. onStrictKeyboardHandler('onExecute'),
  7462. onStrictKeyboardHandler('onEscape'),
  7463. onStrictHandler('onOpenMenu'),
  7464. onStrictHandler('onOpenSubmenu'),
  7465. onHandler('onRepositionMenu'),
  7466. onHandler('onCollapseMenu'),
  7467. defaulted('highlightOnOpen', HighlightOnOpen.HighlightMenuAndItem),
  7468. requiredObjOf('data', [
  7469. required$1('primary'),
  7470. required$1('menus'),
  7471. required$1('expansions')
  7472. ]),
  7473. defaulted('fakeFocus', false),
  7474. onHandler('onHighlightItem'),
  7475. onHandler('onDehighlightItem'),
  7476. onHandler('onHover'),
  7477. tieredMenuMarkers(),
  7478. required$1('dom'),
  7479. defaulted('navigateOnHover', true),
  7480. defaulted('stayInDom', false),
  7481. field('tmenuBehaviours', [
  7482. Keying,
  7483. Highlighting,
  7484. Composing,
  7485. Replacing
  7486. ]),
  7487. defaulted('eventOrder', {})
  7488. ],
  7489. apis: {
  7490. collapseMenu: (apis, tmenu) => {
  7491. apis.collapseMenu(tmenu);
  7492. },
  7493. highlightPrimary: (apis, tmenu) => {
  7494. apis.highlightPrimary(tmenu);
  7495. },
  7496. repositionMenus: (apis, tmenu) => {
  7497. apis.repositionMenus(tmenu);
  7498. }
  7499. },
  7500. factory: make$6,
  7501. extraApis: {
  7502. tieredData,
  7503. singleData,
  7504. collapseItem
  7505. }
  7506. });
  7507. const makeMenu = (detail, menuSandbox, placementSpec, menuSpec, getBounds) => {
  7508. const lazySink = () => detail.lazySink(menuSandbox);
  7509. const layouts = menuSpec.type === 'horizontal' ? {
  7510. layouts: {
  7511. onLtr: () => belowOrAbove(),
  7512. onRtl: () => belowOrAboveRtl()
  7513. }
  7514. } : {};
  7515. const isFirstTierSubmenu = triggeringPaths => triggeringPaths.length === 2;
  7516. const getSubmenuLayouts = triggeringPaths => isFirstTierSubmenu(triggeringPaths) ? layouts : {};
  7517. return tieredMenu.sketch({
  7518. dom: { tag: 'div' },
  7519. data: menuSpec.data,
  7520. markers: menuSpec.menu.markers,
  7521. highlightOnOpen: menuSpec.menu.highlightOnOpen,
  7522. fakeFocus: menuSpec.menu.fakeFocus,
  7523. onEscape: () => {
  7524. Sandboxing.close(menuSandbox);
  7525. detail.onEscape.map(handler => handler(menuSandbox));
  7526. return Optional.some(true);
  7527. },
  7528. onExecute: () => {
  7529. return Optional.some(true);
  7530. },
  7531. onOpenMenu: (tmenu, menu) => {
  7532. Positioning.positionWithinBounds(lazySink().getOrDie(), menu, placementSpec, getBounds());
  7533. },
  7534. onOpenSubmenu: (tmenu, item, submenu, triggeringPaths) => {
  7535. const sink = lazySink().getOrDie();
  7536. Positioning.position(sink, submenu, {
  7537. anchor: {
  7538. type: 'submenu',
  7539. item,
  7540. ...getSubmenuLayouts(triggeringPaths)
  7541. }
  7542. });
  7543. },
  7544. onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
  7545. const sink = lazySink().getOrDie();
  7546. Positioning.positionWithinBounds(sink, primaryMenu, placementSpec, getBounds());
  7547. each$1(submenuTriggers, st => {
  7548. const submenuLayouts = getSubmenuLayouts(st.triggeringPath);
  7549. Positioning.position(sink, st.triggeredMenu, {
  7550. anchor: {
  7551. type: 'submenu',
  7552. item: st.triggeringItem,
  7553. ...submenuLayouts
  7554. }
  7555. });
  7556. });
  7557. }
  7558. });
  7559. };
  7560. const factory$o = (detail, spec) => {
  7561. const isPartOfRelated = (sandbox, queryElem) => {
  7562. const related = detail.getRelated(sandbox);
  7563. return related.exists(rel => isPartOf$1(rel, queryElem));
  7564. };
  7565. const setContent = (sandbox, thing) => {
  7566. Sandboxing.setContent(sandbox, thing);
  7567. };
  7568. const showAt = (sandbox, thing, placementSpec) => {
  7569. const getBounds = Optional.none;
  7570. showWithinBounds(sandbox, thing, placementSpec, getBounds);
  7571. };
  7572. const showWithinBounds = (sandbox, thing, placementSpec, getBounds) => {
  7573. const sink = detail.lazySink(sandbox).getOrDie();
  7574. Sandboxing.openWhileCloaked(sandbox, thing, () => Positioning.positionWithinBounds(sink, sandbox, placementSpec, getBounds()));
  7575. Representing.setValue(sandbox, Optional.some({
  7576. mode: 'position',
  7577. config: placementSpec,
  7578. getBounds
  7579. }));
  7580. };
  7581. const showMenuAt = (sandbox, placementSpec, menuSpec) => {
  7582. showMenuWithinBounds(sandbox, placementSpec, menuSpec, Optional.none);
  7583. };
  7584. const showMenuWithinBounds = (sandbox, placementSpec, menuSpec, getBounds) => {
  7585. const menu = makeMenu(detail, sandbox, placementSpec, menuSpec, getBounds);
  7586. Sandboxing.open(sandbox, menu);
  7587. Representing.setValue(sandbox, Optional.some({
  7588. mode: 'menu',
  7589. menu
  7590. }));
  7591. };
  7592. const hide = sandbox => {
  7593. if (Sandboxing.isOpen(sandbox)) {
  7594. Representing.setValue(sandbox, Optional.none());
  7595. Sandboxing.close(sandbox);
  7596. }
  7597. };
  7598. const getContent = sandbox => Sandboxing.getState(sandbox);
  7599. const reposition = sandbox => {
  7600. if (Sandboxing.isOpen(sandbox)) {
  7601. Representing.getValue(sandbox).each(state => {
  7602. switch (state.mode) {
  7603. case 'menu':
  7604. Sandboxing.getState(sandbox).each(tieredMenu.repositionMenus);
  7605. break;
  7606. case 'position':
  7607. const sink = detail.lazySink(sandbox).getOrDie();
  7608. Positioning.positionWithinBounds(sink, sandbox, state.config, state.getBounds());
  7609. break;
  7610. }
  7611. });
  7612. }
  7613. };
  7614. const apis = {
  7615. setContent,
  7616. showAt,
  7617. showWithinBounds,
  7618. showMenuAt,
  7619. showMenuWithinBounds,
  7620. hide,
  7621. getContent,
  7622. reposition,
  7623. isOpen: Sandboxing.isOpen
  7624. };
  7625. return {
  7626. uid: detail.uid,
  7627. dom: detail.dom,
  7628. behaviours: augment(detail.inlineBehaviours, [
  7629. Sandboxing.config({
  7630. isPartOf: (sandbox, data, queryElem) => {
  7631. return isPartOf$1(data, queryElem) || isPartOfRelated(sandbox, queryElem);
  7632. },
  7633. getAttachPoint: sandbox => {
  7634. return detail.lazySink(sandbox).getOrDie();
  7635. },
  7636. onOpen: sandbox => {
  7637. detail.onShow(sandbox);
  7638. },
  7639. onClose: sandbox => {
  7640. detail.onHide(sandbox);
  7641. }
  7642. }),
  7643. Representing.config({
  7644. store: {
  7645. mode: 'memory',
  7646. initialValue: Optional.none()
  7647. }
  7648. }),
  7649. Receiving.config({
  7650. channels: {
  7651. ...receivingChannel$1({
  7652. isExtraPart: spec.isExtraPart,
  7653. ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
  7654. }),
  7655. ...receivingChannel({
  7656. ...detail.fireRepositionEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({}),
  7657. doReposition: reposition
  7658. })
  7659. }
  7660. })
  7661. ]),
  7662. eventOrder: detail.eventOrder,
  7663. apis
  7664. };
  7665. };
  7666. const InlineView = single({
  7667. name: 'InlineView',
  7668. configFields: [
  7669. required$1('lazySink'),
  7670. onHandler('onShow'),
  7671. onHandler('onHide'),
  7672. optionFunction('onEscape'),
  7673. field('inlineBehaviours', [
  7674. Sandboxing,
  7675. Representing,
  7676. Receiving
  7677. ]),
  7678. optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
  7679. optionObjOf('fireRepositionEventInstead', [defaulted('event', repositionRequested())]),
  7680. defaulted('getRelated', Optional.none),
  7681. defaulted('isExtraPart', never),
  7682. defaulted('eventOrder', Optional.none)
  7683. ],
  7684. factory: factory$o,
  7685. apis: {
  7686. showAt: (apis, component, anchor, thing) => {
  7687. apis.showAt(component, anchor, thing);
  7688. },
  7689. showWithinBounds: (apis, component, anchor, thing, bounds) => {
  7690. apis.showWithinBounds(component, anchor, thing, bounds);
  7691. },
  7692. showMenuAt: (apis, component, anchor, menuSpec) => {
  7693. apis.showMenuAt(component, anchor, menuSpec);
  7694. },
  7695. showMenuWithinBounds: (apis, component, anchor, menuSpec, bounds) => {
  7696. apis.showMenuWithinBounds(component, anchor, menuSpec, bounds);
  7697. },
  7698. hide: (apis, component) => {
  7699. apis.hide(component);
  7700. },
  7701. isOpen: (apis, component) => apis.isOpen(component),
  7702. getContent: (apis, component) => apis.getContent(component),
  7703. setContent: (apis, component, thing) => {
  7704. apis.setContent(component, thing);
  7705. },
  7706. reposition: (apis, component) => {
  7707. apis.reposition(component);
  7708. }
  7709. }
  7710. });
  7711. var global$9 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  7712. const factory$n = detail => {
  7713. const events = events$a(detail.action);
  7714. const tag = detail.dom.tag;
  7715. const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
  7716. const getModAttributes = () => {
  7717. if (tag === 'button') {
  7718. const type = lookupAttr('type').getOr('button');
  7719. const roleAttrs = lookupAttr('role').map(role => ({ role })).getOr({});
  7720. return {
  7721. type,
  7722. ...roleAttrs
  7723. };
  7724. } else {
  7725. const role = detail.role.getOr(lookupAttr('role').getOr('button'));
  7726. return { role };
  7727. }
  7728. };
  7729. return {
  7730. uid: detail.uid,
  7731. dom: detail.dom,
  7732. components: detail.components,
  7733. events,
  7734. behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
  7735. Focusing.config({}),
  7736. Keying.config({
  7737. mode: 'execution',
  7738. useSpace: true,
  7739. useEnter: true
  7740. })
  7741. ]),
  7742. domModification: { attributes: getModAttributes() },
  7743. eventOrder: detail.eventOrder
  7744. };
  7745. };
  7746. const Button = single({
  7747. name: 'Button',
  7748. factory: factory$n,
  7749. configFields: [
  7750. defaulted('uid', undefined),
  7751. required$1('dom'),
  7752. defaulted('components', []),
  7753. SketchBehaviours.field('buttonBehaviours', [
  7754. Focusing,
  7755. Keying
  7756. ]),
  7757. option$3('action'),
  7758. option$3('role'),
  7759. defaulted('eventOrder', {})
  7760. ]
  7761. });
  7762. const getAttrs = elem => {
  7763. const attributes = elem.dom.attributes !== undefined ? elem.dom.attributes : [];
  7764. return foldl(attributes, (b, attr) => {
  7765. if (attr.name === 'class') {
  7766. return b;
  7767. } else {
  7768. return {
  7769. ...b,
  7770. [attr.name]: attr.value
  7771. };
  7772. }
  7773. }, {});
  7774. };
  7775. const getClasses = elem => Array.prototype.slice.call(elem.dom.classList, 0);
  7776. const fromHtml = html => {
  7777. const elem = SugarElement.fromHtml(html);
  7778. const children$1 = children(elem);
  7779. const attrs = getAttrs(elem);
  7780. const classes = getClasses(elem);
  7781. const contents = children$1.length === 0 ? {} : { innerHtml: get$9(elem) };
  7782. return {
  7783. tag: name$3(elem),
  7784. classes,
  7785. attributes: attrs,
  7786. ...contents
  7787. };
  7788. };
  7789. const record = spec => {
  7790. const uid = isSketchSpec(spec) && hasNonNullableKey(spec, 'uid') ? spec.uid : generate$5('memento');
  7791. const get = anyInSystem => anyInSystem.getSystem().getByUid(uid).getOrDie();
  7792. const getOpt = anyInSystem => anyInSystem.getSystem().getByUid(uid).toOptional();
  7793. const asSpec = () => ({
  7794. ...spec,
  7795. uid
  7796. });
  7797. return {
  7798. get,
  7799. getOpt,
  7800. asSpec
  7801. };
  7802. };
  7803. /*! @license DOMPurify 3.1.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.7/LICENSE */
  7804. const {
  7805. entries,
  7806. setPrototypeOf,
  7807. isFrozen,
  7808. getPrototypeOf,
  7809. getOwnPropertyDescriptor
  7810. } = Object;
  7811. let {
  7812. freeze,
  7813. seal,
  7814. create: create$1
  7815. } = Object; // eslint-disable-line import/no-mutable-exports
  7816. let {
  7817. apply,
  7818. construct
  7819. } = typeof Reflect !== 'undefined' && Reflect;
  7820. if (!freeze) {
  7821. freeze = function freeze(x) {
  7822. return x;
  7823. };
  7824. }
  7825. if (!seal) {
  7826. seal = function seal(x) {
  7827. return x;
  7828. };
  7829. }
  7830. if (!apply) {
  7831. apply = function apply(fun, thisValue, args) {
  7832. return fun.apply(thisValue, args);
  7833. };
  7834. }
  7835. if (!construct) {
  7836. construct = function construct(Func, args) {
  7837. return new Func(...args);
  7838. };
  7839. }
  7840. const arrayForEach = unapply(Array.prototype.forEach);
  7841. const arrayPop = unapply(Array.prototype.pop);
  7842. const arrayPush = unapply(Array.prototype.push);
  7843. const stringToLowerCase = unapply(String.prototype.toLowerCase);
  7844. const stringToString = unapply(String.prototype.toString);
  7845. const stringMatch = unapply(String.prototype.match);
  7846. const stringReplace = unapply(String.prototype.replace);
  7847. const stringIndexOf = unapply(String.prototype.indexOf);
  7848. const stringTrim = unapply(String.prototype.trim);
  7849. const objectHasOwnProperty = unapply(Object.prototype.hasOwnProperty);
  7850. const regExpTest = unapply(RegExp.prototype.test);
  7851. const typeErrorCreate = unconstruct(TypeError);
  7852. /**
  7853. * Creates a new function that calls the given function with a specified thisArg and arguments.
  7854. *
  7855. * @param {Function} func - The function to be wrapped and called.
  7856. * @returns {Function} A new function that calls the given function with a specified thisArg and arguments.
  7857. */
  7858. function unapply(func) {
  7859. return function (thisArg) {
  7860. for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  7861. args[_key - 1] = arguments[_key];
  7862. }
  7863. return apply(func, thisArg, args);
  7864. };
  7865. }
  7866. /**
  7867. * Creates a new function that constructs an instance of the given constructor function with the provided arguments.
  7868. *
  7869. * @param {Function} func - The constructor function to be wrapped and called.
  7870. * @returns {Function} A new function that constructs an instance of the given constructor function with the provided arguments.
  7871. */
  7872. function unconstruct(func) {
  7873. return function () {
  7874. for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  7875. args[_key2] = arguments[_key2];
  7876. }
  7877. return construct(func, args);
  7878. };
  7879. }
  7880. /**
  7881. * Add properties to a lookup table
  7882. *
  7883. * @param {Object} set - The set to which elements will be added.
  7884. * @param {Array} array - The array containing elements to be added to the set.
  7885. * @param {Function} transformCaseFunc - An optional function to transform the case of each element before adding to the set.
  7886. * @returns {Object} The modified set with added elements.
  7887. */
  7888. function addToSet(set, array) {
  7889. let transformCaseFunc = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : stringToLowerCase;
  7890. if (setPrototypeOf) {
  7891. // Make 'in' and truthy checks like Boolean(set.constructor)
  7892. // independent of any properties defined on Object.prototype.
  7893. // Prevent prototype setters from intercepting set as a this value.
  7894. setPrototypeOf(set, null);
  7895. }
  7896. let l = array.length;
  7897. while (l--) {
  7898. let element = array[l];
  7899. if (typeof element === 'string') {
  7900. const lcElement = transformCaseFunc(element);
  7901. if (lcElement !== element) {
  7902. // Config presets (e.g. tags.js, attrs.js) are immutable.
  7903. if (!isFrozen(array)) {
  7904. array[l] = lcElement;
  7905. }
  7906. element = lcElement;
  7907. }
  7908. }
  7909. set[element] = true;
  7910. }
  7911. return set;
  7912. }
  7913. /**
  7914. * Clean up an array to harden against CSPP
  7915. *
  7916. * @param {Array} array - The array to be cleaned.
  7917. * @returns {Array} The cleaned version of the array
  7918. */
  7919. function cleanArray(array) {
  7920. for (let index = 0; index < array.length; index++) {
  7921. const isPropertyExist = objectHasOwnProperty(array, index);
  7922. if (!isPropertyExist) {
  7923. array[index] = null;
  7924. }
  7925. }
  7926. return array;
  7927. }
  7928. /**
  7929. * Shallow clone an object
  7930. *
  7931. * @param {Object} object - The object to be cloned.
  7932. * @returns {Object} A new object that copies the original.
  7933. */
  7934. function clone(object) {
  7935. const newObject = create$1(null);
  7936. for (const [property, value] of entries(object)) {
  7937. const isPropertyExist = objectHasOwnProperty(object, property);
  7938. if (isPropertyExist) {
  7939. if (Array.isArray(value)) {
  7940. newObject[property] = cleanArray(value);
  7941. } else if (value && typeof value === 'object' && value.constructor === Object) {
  7942. newObject[property] = clone(value);
  7943. } else {
  7944. newObject[property] = value;
  7945. }
  7946. }
  7947. }
  7948. return newObject;
  7949. }
  7950. /**
  7951. * This method automatically checks if the prop is function or getter and behaves accordingly.
  7952. *
  7953. * @param {Object} object - The object to look up the getter function in its prototype chain.
  7954. * @param {String} prop - The property name for which to find the getter function.
  7955. * @returns {Function} The getter function found in the prototype chain or a fallback function.
  7956. */
  7957. function lookupGetter(object, prop) {
  7958. while (object !== null) {
  7959. const desc = getOwnPropertyDescriptor(object, prop);
  7960. if (desc) {
  7961. if (desc.get) {
  7962. return unapply(desc.get);
  7963. }
  7964. if (typeof desc.value === 'function') {
  7965. return unapply(desc.value);
  7966. }
  7967. }
  7968. object = getPrototypeOf(object);
  7969. }
  7970. function fallbackValue() {
  7971. return null;
  7972. }
  7973. return fallbackValue;
  7974. }
  7975. const html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
  7976. // SVG
  7977. const svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);
  7978. const svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
  7979. // List of SVG elements that are disallowed by default.
  7980. // We still need to know them so that we can do namespace
  7981. // checks properly in case one wants to add them to
  7982. // allow-list.
  7983. const svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);
  7984. const mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']);
  7985. // Similarly to SVG, we want to know all MathML elements,
  7986. // even those that we disallow by default.
  7987. const mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);
  7988. const text$1 = freeze(['#text']);
  7989. const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns', 'slot']);
  7990. const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
  7991. const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
  7992. const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
  7993. // eslint-disable-next-line unicorn/better-regex
  7994. const MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
  7995. const ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
  7996. const TMPLIT_EXPR = seal(/\${[\w\W]*}/gm);
  7997. const DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
  7998. const ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
  7999. const IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
  8000. );
  8001. const IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
  8002. const ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
  8003. );
  8004. const DOCTYPE_NAME = seal(/^html$/i);
  8005. const CUSTOM_ELEMENT = seal(/^[a-z][.\w]*(-[.\w]+)+$/i);
  8006. var EXPRESSIONS = /*#__PURE__*/Object.freeze({
  8007. __proto__: null,
  8008. MUSTACHE_EXPR: MUSTACHE_EXPR,
  8009. ERB_EXPR: ERB_EXPR,
  8010. TMPLIT_EXPR: TMPLIT_EXPR,
  8011. DATA_ATTR: DATA_ATTR,
  8012. ARIA_ATTR: ARIA_ATTR,
  8013. IS_ALLOWED_URI: IS_ALLOWED_URI,
  8014. IS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,
  8015. ATTR_WHITESPACE: ATTR_WHITESPACE,
  8016. DOCTYPE_NAME: DOCTYPE_NAME,
  8017. CUSTOM_ELEMENT: CUSTOM_ELEMENT
  8018. });
  8019. // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
  8020. const NODE_TYPE = {
  8021. element: 1,
  8022. attribute: 2,
  8023. text: 3,
  8024. cdataSection: 4,
  8025. entityReference: 5,
  8026. // Deprecated
  8027. entityNode: 6,
  8028. // Deprecated
  8029. progressingInstruction: 7,
  8030. comment: 8,
  8031. document: 9,
  8032. documentType: 10,
  8033. documentFragment: 11,
  8034. notation: 12 // Deprecated
  8035. };
  8036. const getGlobal = function getGlobal() {
  8037. return typeof window === 'undefined' ? null : window;
  8038. };
  8039. /**
  8040. * Creates a no-op policy for internal use only.
  8041. * Don't export this function outside this module!
  8042. * @param {TrustedTypePolicyFactory} trustedTypes The policy factory.
  8043. * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).
  8044. * @return {TrustedTypePolicy} The policy created (or null, if Trusted Types
  8045. * are not supported or creating the policy failed).
  8046. */
  8047. const _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {
  8048. if (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
  8049. return null;
  8050. }
  8051. // Allow the callers to control the unique policy name
  8052. // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
  8053. // Policy creation with duplicate names throws in Trusted Types.
  8054. let suffix = null;
  8055. const ATTR_NAME = 'data-tt-policy-suffix';
  8056. if (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {
  8057. suffix = purifyHostElement.getAttribute(ATTR_NAME);
  8058. }
  8059. const policyName = 'dompurify' + (suffix ? '#' + suffix : '');
  8060. try {
  8061. return trustedTypes.createPolicy(policyName, {
  8062. createHTML(html) {
  8063. return html;
  8064. },
  8065. createScriptURL(scriptUrl) {
  8066. return scriptUrl;
  8067. }
  8068. });
  8069. } catch (_) {
  8070. // Policy creation failed (most likely another DOMPurify script has
  8071. // already run). Skip creating the policy, as this will only cause errors
  8072. // if TT are enforced.
  8073. console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
  8074. return null;
  8075. }
  8076. };
  8077. function createDOMPurify() {
  8078. let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
  8079. const DOMPurify = root => createDOMPurify(root);
  8080. /**
  8081. * Version label, exposed for easier checks
  8082. * if DOMPurify is up to date or not
  8083. */
  8084. DOMPurify.version = '3.1.7';
  8085. /**
  8086. * Array of elements that DOMPurify removed during sanitation.
  8087. * Empty if nothing was removed.
  8088. */
  8089. DOMPurify.removed = [];
  8090. if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document) {
  8091. // Not running in a browser, provide a factory function
  8092. // so that you can pass your own Window
  8093. DOMPurify.isSupported = false;
  8094. return DOMPurify;
  8095. }
  8096. let {
  8097. document
  8098. } = window;
  8099. const originalDocument = document;
  8100. const currentScript = originalDocument.currentScript;
  8101. const {
  8102. DocumentFragment,
  8103. HTMLTemplateElement,
  8104. Node,
  8105. Element,
  8106. NodeFilter,
  8107. NamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,
  8108. HTMLFormElement,
  8109. DOMParser,
  8110. trustedTypes
  8111. } = window;
  8112. const ElementPrototype = Element.prototype;
  8113. const cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
  8114. const remove = lookupGetter(ElementPrototype, 'remove');
  8115. const getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
  8116. const getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
  8117. const getParentNode = lookupGetter(ElementPrototype, 'parentNode');
  8118. // As per issue #47, the web-components registry is inherited by a
  8119. // new document created via createHTMLDocument. As per the spec
  8120. // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
  8121. // a new empty registry is used when creating a template contents owner
  8122. // document, so we use that as our parent document to ensure nothing
  8123. // is inherited.
  8124. if (typeof HTMLTemplateElement === 'function') {
  8125. const template = document.createElement('template');
  8126. if (template.content && template.content.ownerDocument) {
  8127. document = template.content.ownerDocument;
  8128. }
  8129. }
  8130. let trustedTypesPolicy;
  8131. let emptyHTML = '';
  8132. const {
  8133. implementation,
  8134. createNodeIterator,
  8135. createDocumentFragment,
  8136. getElementsByTagName
  8137. } = document;
  8138. const {
  8139. importNode
  8140. } = originalDocument;
  8141. let hooks = {};
  8142. /**
  8143. * Expose whether this browser supports running the full DOMPurify.
  8144. */
  8145. DOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;
  8146. const {
  8147. MUSTACHE_EXPR,
  8148. ERB_EXPR,
  8149. TMPLIT_EXPR,
  8150. DATA_ATTR,
  8151. ARIA_ATTR,
  8152. IS_SCRIPT_OR_DATA,
  8153. ATTR_WHITESPACE,
  8154. CUSTOM_ELEMENT
  8155. } = EXPRESSIONS;
  8156. let {
  8157. IS_ALLOWED_URI: IS_ALLOWED_URI$1
  8158. } = EXPRESSIONS;
  8159. /**
  8160. * We consider the elements and attributes below to be safe. Ideally
  8161. * don't add any new ones but feel free to remove unwanted ones.
  8162. */
  8163. /* allowed element names */
  8164. let ALLOWED_TAGS = null;
  8165. const DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text$1]);
  8166. /* Allowed attribute names */
  8167. let ALLOWED_ATTR = null;
  8168. const DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);
  8169. /*
  8170. * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.
  8171. * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)
  8172. * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)
  8173. * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.
  8174. */
  8175. let CUSTOM_ELEMENT_HANDLING = Object.seal(create$1(null, {
  8176. tagNameCheck: {
  8177. writable: true,
  8178. configurable: false,
  8179. enumerable: true,
  8180. value: null
  8181. },
  8182. attributeNameCheck: {
  8183. writable: true,
  8184. configurable: false,
  8185. enumerable: true,
  8186. value: null
  8187. },
  8188. allowCustomizedBuiltInElements: {
  8189. writable: true,
  8190. configurable: false,
  8191. enumerable: true,
  8192. value: false
  8193. }
  8194. }));
  8195. /* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
  8196. let FORBID_TAGS = null;
  8197. /* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */
  8198. let FORBID_ATTR = null;
  8199. /* Decide if ARIA attributes are okay */
  8200. let ALLOW_ARIA_ATTR = true;
  8201. /* Decide if custom data attributes are okay */
  8202. let ALLOW_DATA_ATTR = true;
  8203. /* Decide if unknown protocols are okay */
  8204. let ALLOW_UNKNOWN_PROTOCOLS = false;
  8205. /* Decide if self-closing tags in attributes are allowed.
  8206. * Usually removed due to a mXSS issue in jQuery 3.0 */
  8207. let ALLOW_SELF_CLOSE_IN_ATTR = true;
  8208. /* Output should be safe for common template engines.
  8209. * This means, DOMPurify removes data attributes, mustaches and ERB
  8210. */
  8211. let SAFE_FOR_TEMPLATES = false;
  8212. /* Output should be safe even for XML used within HTML and alike.
  8213. * This means, DOMPurify removes comments when containing risky content.
  8214. */
  8215. let SAFE_FOR_XML = true;
  8216. /* Decide if document with <html>... should be returned */
  8217. let WHOLE_DOCUMENT = false;
  8218. /* Track whether config is already set on this instance of DOMPurify. */
  8219. let SET_CONFIG = false;
  8220. /* Decide if all elements (e.g. style, script) must be children of
  8221. * document.body. By default, browsers might move them to document.head */
  8222. let FORCE_BODY = false;
  8223. /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
  8224. * string (or a TrustedHTML object if Trusted Types are supported).
  8225. * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
  8226. */
  8227. let RETURN_DOM = false;
  8228. /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
  8229. * string (or a TrustedHTML object if Trusted Types are supported) */
  8230. let RETURN_DOM_FRAGMENT = false;
  8231. /* Try to return a Trusted Type object instead of a string, return a string in
  8232. * case Trusted Types are not supported */
  8233. let RETURN_TRUSTED_TYPE = false;
  8234. /* Output should be free from DOM clobbering attacks?
  8235. * This sanitizes markups named with colliding, clobberable built-in DOM APIs.
  8236. */
  8237. let SANITIZE_DOM = true;
  8238. /* Achieve full DOM Clobbering protection by isolating the namespace of named
  8239. * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.
  8240. *
  8241. * HTML/DOM spec rules that enable DOM Clobbering:
  8242. * - Named Access on Window (§7.3.3)
  8243. * - DOM Tree Accessors (§3.1.5)
  8244. * - Form Element Parent-Child Relations (§4.10.3)
  8245. * - Iframe srcdoc / Nested WindowProxies (§4.8.5)
  8246. * - HTMLCollection (§4.2.10.2)
  8247. *
  8248. * Namespace isolation is implemented by prefixing `id` and `name` attributes
  8249. * with a constant string, i.e., `user-content-`
  8250. */
  8251. let SANITIZE_NAMED_PROPS = false;
  8252. const SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';
  8253. /* Keep element content when removing element? */
  8254. let KEEP_CONTENT = true;
  8255. /* If a `Node` is passed to sanitize(), then performs sanitization in-place instead
  8256. * of importing it into a new Document and returning a sanitized copy */
  8257. let IN_PLACE = false;
  8258. /* Allow usage of profiles like html, svg and mathMl */
  8259. let USE_PROFILES = {};
  8260. /* Tags to ignore content of when KEEP_CONTENT is true */
  8261. let FORBID_CONTENTS = null;
  8262. const DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
  8263. /* Tags that are safe for data: URIs */
  8264. let DATA_URI_TAGS = null;
  8265. const DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
  8266. /* Attributes safe for values like "javascript:" */
  8267. let URI_SAFE_ATTRIBUTES = null;
  8268. const DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);
  8269. const MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
  8270. const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
  8271. const HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
  8272. /* Document namespace */
  8273. let NAMESPACE = HTML_NAMESPACE;
  8274. let IS_EMPTY_INPUT = false;
  8275. /* Allowed XHTML+XML namespaces */
  8276. let ALLOWED_NAMESPACES = null;
  8277. const DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);
  8278. /* Parsing of strict XHTML documents */
  8279. let PARSER_MEDIA_TYPE = null;
  8280. const SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];
  8281. const DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
  8282. let transformCaseFunc = null;
  8283. /* Keep a reference to config to pass to hooks */
  8284. let CONFIG = null;
  8285. /* Ideally, do not touch anything below this line */
  8286. /* ______________________________________________ */
  8287. const formElement = document.createElement('form');
  8288. const isRegexOrFunction = function isRegexOrFunction(testValue) {
  8289. return testValue instanceof RegExp || testValue instanceof Function;
  8290. };
  8291. /**
  8292. * _parseConfig
  8293. *
  8294. * @param {Object} cfg optional config literal
  8295. */
  8296. // eslint-disable-next-line complexity
  8297. const _parseConfig = function _parseConfig() {
  8298. let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  8299. if (CONFIG && CONFIG === cfg) {
  8300. return;
  8301. }
  8302. /* Shield configuration object from tampering */
  8303. if (!cfg || typeof cfg !== 'object') {
  8304. cfg = {};
  8305. }
  8306. /* Shield configuration object from prototype pollution */
  8307. cfg = clone(cfg);
  8308. PARSER_MEDIA_TYPE =
  8309. // eslint-disable-next-line unicorn/prefer-includes
  8310. SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? DEFAULT_PARSER_MEDIA_TYPE : cfg.PARSER_MEDIA_TYPE;
  8311. // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.
  8312. transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;
  8313. /* Set configuration parameters */
  8314. ALLOWED_TAGS = objectHasOwnProperty(cfg, 'ALLOWED_TAGS') ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;
  8315. ALLOWED_ATTR = objectHasOwnProperty(cfg, 'ALLOWED_ATTR') ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;
  8316. ALLOWED_NAMESPACES = objectHasOwnProperty(cfg, 'ALLOWED_NAMESPACES') ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;
  8317. URI_SAFE_ATTRIBUTES = objectHasOwnProperty(cfg, 'ADD_URI_SAFE_ATTR') ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES),
  8318. // eslint-disable-line indent
  8319. cfg.ADD_URI_SAFE_ATTR,
  8320. // eslint-disable-line indent
  8321. transformCaseFunc // eslint-disable-line indent
  8322. ) // eslint-disable-line indent
  8323. : DEFAULT_URI_SAFE_ATTRIBUTES;
  8324. DATA_URI_TAGS = objectHasOwnProperty(cfg, 'ADD_DATA_URI_TAGS') ? addToSet(clone(DEFAULT_DATA_URI_TAGS),
  8325. // eslint-disable-line indent
  8326. cfg.ADD_DATA_URI_TAGS,
  8327. // eslint-disable-line indent
  8328. transformCaseFunc // eslint-disable-line indent
  8329. ) // eslint-disable-line indent
  8330. : DEFAULT_DATA_URI_TAGS;
  8331. FORBID_CONTENTS = objectHasOwnProperty(cfg, 'FORBID_CONTENTS') ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;
  8332. FORBID_TAGS = objectHasOwnProperty(cfg, 'FORBID_TAGS') ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};
  8333. FORBID_ATTR = objectHasOwnProperty(cfg, 'FORBID_ATTR') ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};
  8334. USE_PROFILES = objectHasOwnProperty(cfg, 'USE_PROFILES') ? cfg.USE_PROFILES : false;
  8335. ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
  8336. ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
  8337. ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
  8338. ALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true
  8339. SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
  8340. SAFE_FOR_XML = cfg.SAFE_FOR_XML !== false; // Default true
  8341. WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
  8342. RETURN_DOM = cfg.RETURN_DOM || false; // Default false
  8343. RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
  8344. RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
  8345. FORCE_BODY = cfg.FORCE_BODY || false; // Default false
  8346. SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
  8347. SANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false
  8348. KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
  8349. IN_PLACE = cfg.IN_PLACE || false; // Default false
  8350. IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;
  8351. NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
  8352. CUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};
  8353. if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
  8354. CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
  8355. }
  8356. if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
  8357. CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
  8358. }
  8359. if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
  8360. CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
  8361. }
  8362. if (SAFE_FOR_TEMPLATES) {
  8363. ALLOW_DATA_ATTR = false;
  8364. }
  8365. if (RETURN_DOM_FRAGMENT) {
  8366. RETURN_DOM = true;
  8367. }
  8368. /* Parse profile info */
  8369. if (USE_PROFILES) {
  8370. ALLOWED_TAGS = addToSet({}, text$1);
  8371. ALLOWED_ATTR = [];
  8372. if (USE_PROFILES.html === true) {
  8373. addToSet(ALLOWED_TAGS, html$1);
  8374. addToSet(ALLOWED_ATTR, html);
  8375. }
  8376. if (USE_PROFILES.svg === true) {
  8377. addToSet(ALLOWED_TAGS, svg$1);
  8378. addToSet(ALLOWED_ATTR, svg);
  8379. addToSet(ALLOWED_ATTR, xml);
  8380. }
  8381. if (USE_PROFILES.svgFilters === true) {
  8382. addToSet(ALLOWED_TAGS, svgFilters);
  8383. addToSet(ALLOWED_ATTR, svg);
  8384. addToSet(ALLOWED_ATTR, xml);
  8385. }
  8386. if (USE_PROFILES.mathMl === true) {
  8387. addToSet(ALLOWED_TAGS, mathMl$1);
  8388. addToSet(ALLOWED_ATTR, mathMl);
  8389. addToSet(ALLOWED_ATTR, xml);
  8390. }
  8391. }
  8392. /* Merge configuration parameters */
  8393. if (cfg.ADD_TAGS) {
  8394. if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
  8395. ALLOWED_TAGS = clone(ALLOWED_TAGS);
  8396. }
  8397. addToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);
  8398. }
  8399. if (cfg.ADD_ATTR) {
  8400. if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
  8401. ALLOWED_ATTR = clone(ALLOWED_ATTR);
  8402. }
  8403. addToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);
  8404. }
  8405. if (cfg.ADD_URI_SAFE_ATTR) {
  8406. addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);
  8407. }
  8408. if (cfg.FORBID_CONTENTS) {
  8409. if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
  8410. FORBID_CONTENTS = clone(FORBID_CONTENTS);
  8411. }
  8412. addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);
  8413. }
  8414. /* Add #text in case KEEP_CONTENT is set to true */
  8415. if (KEEP_CONTENT) {
  8416. ALLOWED_TAGS['#text'] = true;
  8417. }
  8418. /* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */
  8419. if (WHOLE_DOCUMENT) {
  8420. addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
  8421. }
  8422. /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
  8423. if (ALLOWED_TAGS.table) {
  8424. addToSet(ALLOWED_TAGS, ['tbody']);
  8425. delete FORBID_TAGS.tbody;
  8426. }
  8427. if (cfg.TRUSTED_TYPES_POLICY) {
  8428. if (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {
  8429. throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');
  8430. }
  8431. if (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {
  8432. throw typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');
  8433. }
  8434. // Overwrite existing TrustedTypes policy.
  8435. trustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY;
  8436. // Sign local variables required by `sanitize`.
  8437. emptyHTML = trustedTypesPolicy.createHTML('');
  8438. } else {
  8439. // Uninitialized policy, attempt to initialize the internal dompurify policy.
  8440. if (trustedTypesPolicy === undefined) {
  8441. trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);
  8442. }
  8443. // If creating the internal policy succeeded sign internal variables.
  8444. if (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {
  8445. emptyHTML = trustedTypesPolicy.createHTML('');
  8446. }
  8447. }
  8448. // Prevent further manipulation of configuration.
  8449. // Not available in IE8, Safari 5, etc.
  8450. if (freeze) {
  8451. freeze(cfg);
  8452. }
  8453. CONFIG = cfg;
  8454. };
  8455. const MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);
  8456. const HTML_INTEGRATION_POINTS = addToSet({}, ['annotation-xml']);
  8457. // Certain elements are allowed in both SVG and HTML
  8458. // namespace. We need to specify them explicitly
  8459. // so that they don't get erroneously deleted from
  8460. // HTML namespace.
  8461. const COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);
  8462. /* Keep track of all possible SVG and MathML tags
  8463. * so that we can perform the namespace checks
  8464. * correctly. */
  8465. const ALL_SVG_TAGS = addToSet({}, [...svg$1, ...svgFilters, ...svgDisallowed]);
  8466. const ALL_MATHML_TAGS = addToSet({}, [...mathMl$1, ...mathMlDisallowed]);
  8467. /**
  8468. * @param {Element} element a DOM element whose namespace is being checked
  8469. * @returns {boolean} Return false if the element has a
  8470. * namespace that a spec-compliant parser would never
  8471. * return. Return true otherwise.
  8472. */
  8473. const _checkValidNamespace = function _checkValidNamespace(element) {
  8474. let parent = getParentNode(element);
  8475. // In JSDOM, if we're inside shadow DOM, then parentNode
  8476. // can be null. We just simulate parent in this case.
  8477. if (!parent || !parent.tagName) {
  8478. parent = {
  8479. namespaceURI: NAMESPACE,
  8480. tagName: 'template'
  8481. };
  8482. }
  8483. const tagName = stringToLowerCase(element.tagName);
  8484. const parentTagName = stringToLowerCase(parent.tagName);
  8485. if (!ALLOWED_NAMESPACES[element.namespaceURI]) {
  8486. return false;
  8487. }
  8488. if (element.namespaceURI === SVG_NAMESPACE) {
  8489. // The only way to switch from HTML namespace to SVG
  8490. // is via <svg>. If it happens via any other tag, then
  8491. // it should be killed.
  8492. if (parent.namespaceURI === HTML_NAMESPACE) {
  8493. return tagName === 'svg';
  8494. }
  8495. // The only way to switch from MathML to SVG is via`
  8496. // svg if parent is either <annotation-xml> or MathML
  8497. // text integration points.
  8498. if (parent.namespaceURI === MATHML_NAMESPACE) {
  8499. return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
  8500. }
  8501. // We only allow elements that are defined in SVG
  8502. // spec. All others are disallowed in SVG namespace.
  8503. return Boolean(ALL_SVG_TAGS[tagName]);
  8504. }
  8505. if (element.namespaceURI === MATHML_NAMESPACE) {
  8506. // The only way to switch from HTML namespace to MathML
  8507. // is via <math>. If it happens via any other tag, then
  8508. // it should be killed.
  8509. if (parent.namespaceURI === HTML_NAMESPACE) {
  8510. return tagName === 'math';
  8511. }
  8512. // The only way to switch from SVG to MathML is via
  8513. // <math> and HTML integration points
  8514. if (parent.namespaceURI === SVG_NAMESPACE) {
  8515. return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
  8516. }
  8517. // We only allow elements that are defined in MathML
  8518. // spec. All others are disallowed in MathML namespace.
  8519. return Boolean(ALL_MATHML_TAGS[tagName]);
  8520. }
  8521. if (element.namespaceURI === HTML_NAMESPACE) {
  8522. // The only way to switch from SVG to HTML is via
  8523. // HTML integration points, and from MathML to HTML
  8524. // is via MathML text integration points
  8525. if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
  8526. return false;
  8527. }
  8528. if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
  8529. return false;
  8530. }
  8531. // We disallow tags that are specific for MathML
  8532. // or SVG and should never appear in HTML namespace
  8533. return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
  8534. }
  8535. // For XHTML and XML documents that support custom namespaces
  8536. if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {
  8537. return true;
  8538. }
  8539. // The code should never reach this place (this means
  8540. // that the element somehow got namespace that is not
  8541. // HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).
  8542. // Return false just in case.
  8543. return false;
  8544. };
  8545. /**
  8546. * _forceRemove
  8547. *
  8548. * @param {Node} node a DOM node
  8549. */
  8550. const _forceRemove = function _forceRemove(node) {
  8551. arrayPush(DOMPurify.removed, {
  8552. element: node
  8553. });
  8554. try {
  8555. // eslint-disable-next-line unicorn/prefer-dom-node-remove
  8556. getParentNode(node).removeChild(node);
  8557. } catch (_) {
  8558. remove(node);
  8559. }
  8560. };
  8561. /**
  8562. * _removeAttribute
  8563. *
  8564. * @param {String} name an Attribute name
  8565. * @param {Node} node a DOM node
  8566. */
  8567. const _removeAttribute = function _removeAttribute(name, node) {
  8568. try {
  8569. arrayPush(DOMPurify.removed, {
  8570. attribute: node.getAttributeNode(name),
  8571. from: node
  8572. });
  8573. } catch (_) {
  8574. arrayPush(DOMPurify.removed, {
  8575. attribute: null,
  8576. from: node
  8577. });
  8578. }
  8579. node.removeAttribute(name);
  8580. // We void attribute values for unremovable "is"" attributes
  8581. if (name === 'is' && !ALLOWED_ATTR[name]) {
  8582. if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
  8583. try {
  8584. _forceRemove(node);
  8585. } catch (_) {}
  8586. } else {
  8587. try {
  8588. node.setAttribute(name, '');
  8589. } catch (_) {}
  8590. }
  8591. }
  8592. };
  8593. /**
  8594. * _initDocument
  8595. *
  8596. * @param {String} dirty a string of dirty markup
  8597. * @return {Document} a DOM, filled with the dirty markup
  8598. */
  8599. const _initDocument = function _initDocument(dirty) {
  8600. /* Create a HTML document */
  8601. let doc = null;
  8602. let leadingWhitespace = null;
  8603. if (FORCE_BODY) {
  8604. dirty = '<remove></remove>' + dirty;
  8605. } else {
  8606. /* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */
  8607. const matches = stringMatch(dirty, /^[\r\n\t ]+/);
  8608. leadingWhitespace = matches && matches[0];
  8609. }
  8610. if (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {
  8611. // Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)
  8612. dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
  8613. }
  8614. const dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
  8615. /*
  8616. * Use the DOMParser API by default, fallback later if needs be
  8617. * DOMParser not work for svg when has multiple root element.
  8618. */
  8619. if (NAMESPACE === HTML_NAMESPACE) {
  8620. try {
  8621. doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
  8622. } catch (_) {}
  8623. }
  8624. /* Use createHTMLDocument in case DOMParser is not available */
  8625. if (!doc || !doc.documentElement) {
  8626. doc = implementation.createDocument(NAMESPACE, 'template', null);
  8627. try {
  8628. doc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;
  8629. } catch (_) {
  8630. // Syntax error if dirtyPayload is invalid xml
  8631. }
  8632. }
  8633. const body = doc.body || doc.documentElement;
  8634. if (dirty && leadingWhitespace) {
  8635. body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
  8636. }
  8637. /* Work on whole document or just its body */
  8638. if (NAMESPACE === HTML_NAMESPACE) {
  8639. return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
  8640. }
  8641. return WHOLE_DOCUMENT ? doc.documentElement : body;
  8642. };
  8643. /**
  8644. * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document.
  8645. *
  8646. * @param {Node} root The root element or node to start traversing on.
  8647. * @return {NodeIterator} The created NodeIterator
  8648. */
  8649. const _createNodeIterator = function _createNodeIterator(root) {
  8650. return createNodeIterator.call(root.ownerDocument || root, root,
  8651. // eslint-disable-next-line no-bitwise
  8652. NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
  8653. };
  8654. /**
  8655. * _isClobbered
  8656. *
  8657. * @param {Node} elm element to check for clobbering attacks
  8658. * @return {Boolean} true if clobbered, false if safe
  8659. */
  8660. const _isClobbered = function _isClobbered(elm) {
  8661. return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');
  8662. };
  8663. /**
  8664. * Checks whether the given object is a DOM node.
  8665. *
  8666. * @param {Node} object object to check whether it's a DOM node
  8667. * @return {Boolean} true is object is a DOM node
  8668. */
  8669. const _isNode = function _isNode(object) {
  8670. return typeof Node === 'function' && object instanceof Node;
  8671. };
  8672. /**
  8673. * _executeHook
  8674. * Execute user configurable hooks
  8675. *
  8676. * @param {String} entryPoint Name of the hook's entry point
  8677. * @param {Node} currentNode node to work on with the hook
  8678. * @param {Object} data additional hook parameters
  8679. */
  8680. const _executeHook = function _executeHook(entryPoint, currentNode, data) {
  8681. if (!hooks[entryPoint]) {
  8682. return;
  8683. }
  8684. arrayForEach(hooks[entryPoint], hook => {
  8685. hook.call(DOMPurify, currentNode, data, CONFIG);
  8686. });
  8687. };
  8688. /**
  8689. * _sanitizeElements
  8690. *
  8691. * @protect nodeName
  8692. * @protect textContent
  8693. * @protect removeChild
  8694. *
  8695. * @param {Node} currentNode to check for permission to exist
  8696. * @return {Boolean} true if node was killed, false if left alive
  8697. */
  8698. const _sanitizeElements = function _sanitizeElements(currentNode) {
  8699. let content = null;
  8700. /* Execute a hook if present */
  8701. _executeHook('beforeSanitizeElements', currentNode, null);
  8702. /* Check if element is clobbered or can clobber */
  8703. if (_isClobbered(currentNode)) {
  8704. _forceRemove(currentNode);
  8705. return true;
  8706. }
  8707. /* Now let's check the element's type and name */
  8708. const tagName = transformCaseFunc(currentNode.nodeName);
  8709. /* Execute a hook if present */
  8710. _executeHook('uponSanitizeElement', currentNode, {
  8711. tagName,
  8712. allowedTags: ALLOWED_TAGS
  8713. });
  8714. /* Detect mXSS attempts abusing namespace confusion */
  8715. if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
  8716. _forceRemove(currentNode);
  8717. return true;
  8718. }
  8719. /* Remove any occurrence of processing instructions */
  8720. if (currentNode.nodeType === NODE_TYPE.progressingInstruction) {
  8721. _forceRemove(currentNode);
  8722. return true;
  8723. }
  8724. /* Remove any kind of possibly harmful comments */
  8725. if (SAFE_FOR_XML && currentNode.nodeType === NODE_TYPE.comment && regExpTest(/<[/\w]/g, currentNode.data)) {
  8726. _forceRemove(currentNode);
  8727. return true;
  8728. }
  8729. /* Remove element if anything forbids its presence */
  8730. if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
  8731. /* Check if we have a custom element to handle */
  8732. if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
  8733. if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
  8734. return false;
  8735. }
  8736. if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) {
  8737. return false;
  8738. }
  8739. }
  8740. /* Keep content except for bad-listed elements */
  8741. if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
  8742. const parentNode = getParentNode(currentNode) || currentNode.parentNode;
  8743. const childNodes = getChildNodes(currentNode) || currentNode.childNodes;
  8744. if (childNodes && parentNode) {
  8745. const childCount = childNodes.length;
  8746. for (let i = childCount - 1; i >= 0; --i) {
  8747. const childClone = cloneNode(childNodes[i], true);
  8748. childClone.__removalCount = (currentNode.__removalCount || 0) + 1;
  8749. parentNode.insertBefore(childClone, getNextSibling(currentNode));
  8750. }
  8751. }
  8752. }
  8753. _forceRemove(currentNode);
  8754. return true;
  8755. }
  8756. /* Check whether element has a valid namespace */
  8757. if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
  8758. _forceRemove(currentNode);
  8759. return true;
  8760. }
  8761. /* Make sure that older browsers don't get fallback-tag mXSS */
  8762. if ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\/no(script|embed|frames)/i, currentNode.innerHTML)) {
  8763. _forceRemove(currentNode);
  8764. return true;
  8765. }
  8766. /* Sanitize element content to be template-safe */
  8767. if (SAFE_FOR_TEMPLATES && currentNode.nodeType === NODE_TYPE.text) {
  8768. /* Get the element's text content */
  8769. content = currentNode.textContent;
  8770. arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
  8771. content = stringReplace(content, expr, ' ');
  8772. });
  8773. if (currentNode.textContent !== content) {
  8774. arrayPush(DOMPurify.removed, {
  8775. element: currentNode.cloneNode()
  8776. });
  8777. currentNode.textContent = content;
  8778. }
  8779. }
  8780. /* Execute a hook if present */
  8781. _executeHook('afterSanitizeElements', currentNode, null);
  8782. return false;
  8783. };
  8784. /**
  8785. * _isValidAttribute
  8786. *
  8787. * @param {string} lcTag Lowercase tag name of containing element.
  8788. * @param {string} lcName Lowercase attribute name.
  8789. * @param {string} value Attribute value.
  8790. * @return {Boolean} Returns true if `value` is valid, otherwise false.
  8791. */
  8792. // eslint-disable-next-line complexity
  8793. const _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
  8794. /* Make sure attribute cannot clobber */
  8795. if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
  8796. return false;
  8797. }
  8798. /* Allow valid data-* attributes: At least one character after "-"
  8799. (https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)
  8800. XML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)
  8801. We don't need to check the value; it's always URI safe. */
  8802. if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)) ; else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)) ; else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
  8803. if (
  8804. // First condition does a very basic check if a) it's basically a valid custom element tagname AND
  8805. // b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
  8806. // and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck
  8807. _isBasicCustomElement(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) ||
  8808. // Alternative, second condition checks if it's an `is`-attribute, AND
  8809. // the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck
  8810. lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))) ; else {
  8811. return false;
  8812. }
  8813. /* Check value is safe. First, is attr inert? If so, is safe */
  8814. } else if (URI_SAFE_ATTRIBUTES[lcName]) ; else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]) ; else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))) ; else if (value) {
  8815. return false;
  8816. } else ;
  8817. return true;
  8818. };
  8819. /**
  8820. * _isBasicCustomElement
  8821. * checks if at least one dash is included in tagName, and it's not the first char
  8822. * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name
  8823. *
  8824. * @param {string} tagName name of the tag of the node to sanitize
  8825. * @returns {boolean} Returns true if the tag name meets the basic criteria for a custom element, otherwise false.
  8826. */
  8827. const _isBasicCustomElement = function _isBasicCustomElement(tagName) {
  8828. return tagName !== 'annotation-xml' && stringMatch(tagName, CUSTOM_ELEMENT);
  8829. };
  8830. /**
  8831. * _sanitizeAttributes
  8832. *
  8833. * @protect attributes
  8834. * @protect nodeName
  8835. * @protect removeAttribute
  8836. * @protect setAttribute
  8837. *
  8838. * @param {Node} currentNode to sanitize
  8839. */
  8840. const _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
  8841. /* Execute a hook if present */
  8842. _executeHook('beforeSanitizeAttributes', currentNode, null);
  8843. const {
  8844. attributes
  8845. } = currentNode;
  8846. /* Check if we have attributes; if not we might have a text node */
  8847. if (!attributes) {
  8848. return;
  8849. }
  8850. const hookEvent = {
  8851. attrName: '',
  8852. attrValue: '',
  8853. keepAttr: true,
  8854. allowedAttributes: ALLOWED_ATTR
  8855. };
  8856. let l = attributes.length;
  8857. /* Go backwards over all attributes; safely remove bad ones */
  8858. while (l--) {
  8859. const attr = attributes[l];
  8860. const {
  8861. name,
  8862. namespaceURI,
  8863. value: attrValue
  8864. } = attr;
  8865. const lcName = transformCaseFunc(name);
  8866. let value = name === 'value' ? attrValue : stringTrim(attrValue);
  8867. const initValue = value;
  8868. /* Execute a hook if present */
  8869. hookEvent.attrName = lcName;
  8870. hookEvent.attrValue = value;
  8871. hookEvent.keepAttr = true;
  8872. hookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set
  8873. _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
  8874. value = hookEvent.attrValue;
  8875. /* Did the hooks approve of the attribute? */
  8876. if (hookEvent.forceKeepAttr) {
  8877. continue;
  8878. }
  8879. /* Did the hooks approve of the attribute? */
  8880. if (!hookEvent.keepAttr) {
  8881. _removeAttribute(name, currentNode);
  8882. continue;
  8883. }
  8884. /* Work around a security issue in jQuery 3.0 */
  8885. if (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\/>/i, value)) {
  8886. _removeAttribute(name, currentNode);
  8887. continue;
  8888. }
  8889. /* Sanitize attribute content to be template-safe */
  8890. if (SAFE_FOR_TEMPLATES) {
  8891. arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
  8892. value = stringReplace(value, expr, ' ');
  8893. });
  8894. }
  8895. /* Is `value` valid for this attribute? */
  8896. const lcTag = transformCaseFunc(currentNode.nodeName);
  8897. if (!_isValidAttribute(lcTag, lcName, value)) {
  8898. _removeAttribute(name, currentNode);
  8899. continue;
  8900. }
  8901. /* Full DOM Clobbering protection via namespace isolation,
  8902. * Prefix id and name attributes with `user-content-`
  8903. */
  8904. if (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {
  8905. // Remove the attribute with this value
  8906. _removeAttribute(name, currentNode);
  8907. // Prefix the value and later re-create the attribute with the sanitized value
  8908. value = SANITIZE_NAMED_PROPS_PREFIX + value;
  8909. }
  8910. /* Work around a security issue with comments inside attributes */
  8911. if (SAFE_FOR_XML && regExpTest(/((--!?|])>)|<\/(style|title)/i, value)) {
  8912. _removeAttribute(name, currentNode);
  8913. continue;
  8914. }
  8915. /* Handle attributes that require Trusted Types */
  8916. if (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {
  8917. if (namespaceURI) ; else {
  8918. switch (trustedTypes.getAttributeType(lcTag, lcName)) {
  8919. case 'TrustedHTML':
  8920. {
  8921. value = trustedTypesPolicy.createHTML(value);
  8922. break;
  8923. }
  8924. case 'TrustedScriptURL':
  8925. {
  8926. value = trustedTypesPolicy.createScriptURL(value);
  8927. break;
  8928. }
  8929. }
  8930. }
  8931. }
  8932. /* Handle invalid data-* attribute set by try-catching it */
  8933. if (value !== initValue) {
  8934. try {
  8935. if (namespaceURI) {
  8936. currentNode.setAttributeNS(namespaceURI, name, value);
  8937. } else {
  8938. /* Fallback to setAttribute() for browser-unrecognized namespaces e.g. "x-schema". */
  8939. currentNode.setAttribute(name, value);
  8940. }
  8941. if (_isClobbered(currentNode)) {
  8942. _forceRemove(currentNode);
  8943. } else {
  8944. arrayPop(DOMPurify.removed);
  8945. }
  8946. } catch (_) {}
  8947. }
  8948. }
  8949. /* Execute a hook if present */
  8950. _executeHook('afterSanitizeAttributes', currentNode, null);
  8951. };
  8952. /**
  8953. * _sanitizeShadowDOM
  8954. *
  8955. * @param {DocumentFragment} fragment to iterate over recursively
  8956. */
  8957. const _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
  8958. let shadowNode = null;
  8959. const shadowIterator = _createNodeIterator(fragment);
  8960. /* Execute a hook if present */
  8961. _executeHook('beforeSanitizeShadowDOM', fragment, null);
  8962. while (shadowNode = shadowIterator.nextNode()) {
  8963. /* Execute a hook if present */
  8964. _executeHook('uponSanitizeShadowNode', shadowNode, null);
  8965. /* Sanitize tags and elements */
  8966. if (_sanitizeElements(shadowNode)) {
  8967. continue;
  8968. }
  8969. /* Deep shadow DOM detected */
  8970. if (shadowNode.content instanceof DocumentFragment) {
  8971. _sanitizeShadowDOM(shadowNode.content);
  8972. }
  8973. /* Check attributes, sanitize if necessary */
  8974. _sanitizeAttributes(shadowNode);
  8975. }
  8976. /* Execute a hook if present */
  8977. _executeHook('afterSanitizeShadowDOM', fragment, null);
  8978. };
  8979. /**
  8980. * Sanitize
  8981. * Public method providing core sanitation functionality
  8982. *
  8983. * @param {String|Node} dirty string or DOM node
  8984. * @param {Object} cfg object
  8985. */
  8986. // eslint-disable-next-line complexity
  8987. DOMPurify.sanitize = function (dirty) {
  8988. let cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  8989. let body = null;
  8990. let importedNode = null;
  8991. let currentNode = null;
  8992. let returnNode = null;
  8993. /* Make sure we have a string to sanitize.
  8994. DO NOT return early, as this will return the wrong type if
  8995. the user has requested a DOM object rather than a string */
  8996. IS_EMPTY_INPUT = !dirty;
  8997. if (IS_EMPTY_INPUT) {
  8998. dirty = '<!-->';
  8999. }
  9000. /* Stringify, in case dirty is an object */
  9001. if (typeof dirty !== 'string' && !_isNode(dirty)) {
  9002. if (typeof dirty.toString === 'function') {
  9003. dirty = dirty.toString();
  9004. if (typeof dirty !== 'string') {
  9005. throw typeErrorCreate('dirty is not a string, aborting');
  9006. }
  9007. } else {
  9008. throw typeErrorCreate('toString is not a function');
  9009. }
  9010. }
  9011. /* Return dirty HTML if DOMPurify cannot run */
  9012. if (!DOMPurify.isSupported) {
  9013. return dirty;
  9014. }
  9015. /* Assign config vars */
  9016. if (!SET_CONFIG) {
  9017. _parseConfig(cfg);
  9018. }
  9019. /* Clean up removed elements */
  9020. DOMPurify.removed = [];
  9021. /* Check if dirty is correctly typed for IN_PLACE */
  9022. if (typeof dirty === 'string') {
  9023. IN_PLACE = false;
  9024. }
  9025. if (IN_PLACE) {
  9026. /* Do some early pre-sanitization to avoid unsafe root nodes */
  9027. if (dirty.nodeName) {
  9028. const tagName = transformCaseFunc(dirty.nodeName);
  9029. if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
  9030. throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
  9031. }
  9032. }
  9033. } else if (dirty instanceof Node) {
  9034. /* If dirty is a DOM element, append to an empty document to avoid
  9035. elements being stripped by the parser */
  9036. body = _initDocument('<!---->');
  9037. importedNode = body.ownerDocument.importNode(dirty, true);
  9038. if (importedNode.nodeType === NODE_TYPE.element && importedNode.nodeName === 'BODY') {
  9039. /* Node is already a body, use as is */
  9040. body = importedNode;
  9041. } else if (importedNode.nodeName === 'HTML') {
  9042. body = importedNode;
  9043. } else {
  9044. // eslint-disable-next-line unicorn/prefer-dom-node-append
  9045. body.appendChild(importedNode);
  9046. }
  9047. } else {
  9048. /* Exit directly if we have nothing to do */
  9049. if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT &&
  9050. // eslint-disable-next-line unicorn/prefer-includes
  9051. dirty.indexOf('<') === -1) {
  9052. return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
  9053. }
  9054. /* Initialize the document to work on */
  9055. body = _initDocument(dirty);
  9056. /* Check we have a DOM node from the data */
  9057. if (!body) {
  9058. return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
  9059. }
  9060. }
  9061. /* Remove first element node (ours) if FORCE_BODY is set */
  9062. if (body && FORCE_BODY) {
  9063. _forceRemove(body.firstChild);
  9064. }
  9065. /* Get node iterator */
  9066. const nodeIterator = _createNodeIterator(IN_PLACE ? dirty : body);
  9067. /* Now start iterating over the created document */
  9068. while (currentNode = nodeIterator.nextNode()) {
  9069. /* Sanitize tags and elements */
  9070. if (_sanitizeElements(currentNode)) {
  9071. continue;
  9072. }
  9073. /* Shadow DOM detected, sanitize it */
  9074. if (currentNode.content instanceof DocumentFragment) {
  9075. _sanitizeShadowDOM(currentNode.content);
  9076. }
  9077. /* Check attributes, sanitize if necessary */
  9078. _sanitizeAttributes(currentNode);
  9079. }
  9080. /* If we sanitized `dirty` in-place, return it. */
  9081. if (IN_PLACE) {
  9082. return dirty;
  9083. }
  9084. /* Return sanitized string or DOM */
  9085. if (RETURN_DOM) {
  9086. if (RETURN_DOM_FRAGMENT) {
  9087. returnNode = createDocumentFragment.call(body.ownerDocument);
  9088. while (body.firstChild) {
  9089. // eslint-disable-next-line unicorn/prefer-dom-node-append
  9090. returnNode.appendChild(body.firstChild);
  9091. }
  9092. } else {
  9093. returnNode = body;
  9094. }
  9095. if (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {
  9096. /*
  9097. AdoptNode() is not used because internal state is not reset
  9098. (e.g. the past names map of a HTMLFormElement), this is safe
  9099. in theory but we would rather not risk another attack vector.
  9100. The state that is cloned by importNode() is explicitly defined
  9101. by the specs.
  9102. */
  9103. returnNode = importNode.call(originalDocument, returnNode, true);
  9104. }
  9105. return returnNode;
  9106. }
  9107. let serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
  9108. /* Serialize doctype if allowed */
  9109. if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
  9110. serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
  9111. }
  9112. /* Sanitize final string template-safe */
  9113. if (SAFE_FOR_TEMPLATES) {
  9114. arrayForEach([MUSTACHE_EXPR, ERB_EXPR, TMPLIT_EXPR], expr => {
  9115. serializedHTML = stringReplace(serializedHTML, expr, ' ');
  9116. });
  9117. }
  9118. return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
  9119. };
  9120. /**
  9121. * Public method to set the configuration once
  9122. * setConfig
  9123. *
  9124. * @param {Object} cfg configuration object
  9125. */
  9126. DOMPurify.setConfig = function () {
  9127. let cfg = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  9128. _parseConfig(cfg);
  9129. SET_CONFIG = true;
  9130. };
  9131. /**
  9132. * Public method to remove the configuration
  9133. * clearConfig
  9134. *
  9135. */
  9136. DOMPurify.clearConfig = function () {
  9137. CONFIG = null;
  9138. SET_CONFIG = false;
  9139. };
  9140. /**
  9141. * Public method to check if an attribute value is valid.
  9142. * Uses last set config, if any. Otherwise, uses config defaults.
  9143. * isValidAttribute
  9144. *
  9145. * @param {String} tag Tag name of containing element.
  9146. * @param {String} attr Attribute name.
  9147. * @param {String} value Attribute value.
  9148. * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.
  9149. */
  9150. DOMPurify.isValidAttribute = function (tag, attr, value) {
  9151. /* Initialize shared config vars if necessary. */
  9152. if (!CONFIG) {
  9153. _parseConfig({});
  9154. }
  9155. const lcTag = transformCaseFunc(tag);
  9156. const lcName = transformCaseFunc(attr);
  9157. return _isValidAttribute(lcTag, lcName, value);
  9158. };
  9159. /**
  9160. * AddHook
  9161. * Public method to add DOMPurify hooks
  9162. *
  9163. * @param {String} entryPoint entry point for the hook to add
  9164. * @param {Function} hookFunction function to execute
  9165. */
  9166. DOMPurify.addHook = function (entryPoint, hookFunction) {
  9167. if (typeof hookFunction !== 'function') {
  9168. return;
  9169. }
  9170. hooks[entryPoint] = hooks[entryPoint] || [];
  9171. arrayPush(hooks[entryPoint], hookFunction);
  9172. };
  9173. /**
  9174. * RemoveHook
  9175. * Public method to remove a DOMPurify hook at a given entryPoint
  9176. * (pops it from the stack of hooks if more are present)
  9177. *
  9178. * @param {String} entryPoint entry point for the hook to remove
  9179. * @return {Function} removed(popped) hook
  9180. */
  9181. DOMPurify.removeHook = function (entryPoint) {
  9182. if (hooks[entryPoint]) {
  9183. return arrayPop(hooks[entryPoint]);
  9184. }
  9185. };
  9186. /**
  9187. * RemoveHooks
  9188. * Public method to remove all DOMPurify hooks at a given entryPoint
  9189. *
  9190. * @param {String} entryPoint entry point for the hooks to remove
  9191. */
  9192. DOMPurify.removeHooks = function (entryPoint) {
  9193. if (hooks[entryPoint]) {
  9194. hooks[entryPoint] = [];
  9195. }
  9196. };
  9197. /**
  9198. * RemoveAllHooks
  9199. * Public method to remove all DOMPurify hooks
  9200. */
  9201. DOMPurify.removeAllHooks = function () {
  9202. hooks = {};
  9203. };
  9204. return DOMPurify;
  9205. }
  9206. var purify = createDOMPurify();
  9207. const sanitizeHtmlString = html => purify().sanitize(html);
  9208. var global$8 = tinymce.util.Tools.resolve('tinymce.util.I18n');
  9209. const rtlTransform = {
  9210. 'indent': true,
  9211. 'outdent': true,
  9212. 'table-insert-column-after': true,
  9213. 'table-insert-column-before': true,
  9214. 'paste-column-after': true,
  9215. 'paste-column-before': true,
  9216. 'unordered-list': true,
  9217. 'list-bull-circle': true,
  9218. 'list-bull-default': true,
  9219. 'list-bull-square': true
  9220. };
  9221. const defaultIconName = 'temporary-placeholder';
  9222. const defaultIcon = icons => () => get$g(icons, defaultIconName).getOr('!not found!');
  9223. const getIconName = (name, icons) => {
  9224. const lcName = name.toLowerCase();
  9225. if (global$8.isRtl()) {
  9226. const rtlName = ensureTrailing(lcName, '-rtl');
  9227. return has$2(icons, rtlName) ? rtlName : lcName;
  9228. } else {
  9229. return lcName;
  9230. }
  9231. };
  9232. const lookupIcon = (name, icons) => get$g(icons, getIconName(name, icons));
  9233. const get$2 = (name, iconProvider) => {
  9234. const icons = iconProvider();
  9235. return lookupIcon(name, icons).getOrThunk(defaultIcon(icons));
  9236. };
  9237. const getOr = (name, iconProvider, fallbackIcon) => {
  9238. const icons = iconProvider();
  9239. return lookupIcon(name, icons).or(fallbackIcon).getOrThunk(defaultIcon(icons));
  9240. };
  9241. const needsRtlTransform = iconName => global$8.isRtl() ? has$2(rtlTransform, iconName) : false;
  9242. const addFocusableBehaviour = () => config('add-focusable', [runOnAttached(comp => {
  9243. child(comp.element, 'svg').each(svg => set$9(svg, 'focusable', 'false'));
  9244. })]);
  9245. const renderIcon$3 = (spec, iconName, icons, fallbackIcon) => {
  9246. var _a, _b;
  9247. const rtlIconClasses = needsRtlTransform(iconName) ? ['tox-icon--flip'] : [];
  9248. const iconHtml = get$g(icons, getIconName(iconName, icons)).or(fallbackIcon).getOrThunk(defaultIcon(icons));
  9249. return {
  9250. dom: {
  9251. tag: spec.tag,
  9252. attributes: (_a = spec.attributes) !== null && _a !== void 0 ? _a : {},
  9253. classes: spec.classes.concat(rtlIconClasses),
  9254. innerHtml: iconHtml
  9255. },
  9256. behaviours: derive$1([
  9257. ...(_b = spec.behaviours) !== null && _b !== void 0 ? _b : [],
  9258. addFocusableBehaviour()
  9259. ])
  9260. };
  9261. };
  9262. const render$3 = (iconName, spec, iconProvider, fallbackIcon = Optional.none()) => renderIcon$3(spec, iconName, iconProvider(), fallbackIcon);
  9263. const renderFirst = (iconNames, spec, iconProvider) => {
  9264. const icons = iconProvider();
  9265. const iconName = find$5(iconNames, name => has$2(icons, getIconName(name, icons)));
  9266. return renderIcon$3(spec, iconName.getOr(defaultIconName), icons, Optional.none());
  9267. };
  9268. const notificationIconMap = {
  9269. success: 'checkmark',
  9270. error: 'warning',
  9271. err: 'error',
  9272. warning: 'warning',
  9273. warn: 'warning',
  9274. info: 'info'
  9275. };
  9276. const factory$m = detail => {
  9277. const memBannerText = record({
  9278. dom: fromHtml(`<p>${ sanitizeHtmlString(detail.translationProvider(detail.text)) }</p>`),
  9279. behaviours: derive$1([Replacing.config({})])
  9280. });
  9281. const renderPercentBar = percent => ({
  9282. dom: {
  9283. tag: 'div',
  9284. classes: ['tox-bar'],
  9285. styles: { width: `${ percent }%` }
  9286. }
  9287. });
  9288. const renderPercentText = percent => ({
  9289. dom: {
  9290. tag: 'div',
  9291. classes: ['tox-text'],
  9292. innerHtml: `${ percent }%`
  9293. }
  9294. });
  9295. const memBannerProgress = record({
  9296. dom: {
  9297. tag: 'div',
  9298. classes: detail.progress ? [
  9299. 'tox-progress-bar',
  9300. 'tox-progress-indicator'
  9301. ] : ['tox-progress-bar']
  9302. },
  9303. components: [
  9304. {
  9305. dom: {
  9306. tag: 'div',
  9307. classes: ['tox-bar-container']
  9308. },
  9309. components: [renderPercentBar(0)]
  9310. },
  9311. renderPercentText(0)
  9312. ],
  9313. behaviours: derive$1([Replacing.config({})])
  9314. });
  9315. const updateProgress = (comp, percent) => {
  9316. if (comp.getSystem().isConnected()) {
  9317. memBannerProgress.getOpt(comp).each(progress => {
  9318. Replacing.set(progress, [
  9319. {
  9320. dom: {
  9321. tag: 'div',
  9322. classes: ['tox-bar-container']
  9323. },
  9324. components: [renderPercentBar(percent)]
  9325. },
  9326. renderPercentText(percent)
  9327. ]);
  9328. });
  9329. }
  9330. };
  9331. const updateText = (comp, text) => {
  9332. if (comp.getSystem().isConnected()) {
  9333. const banner = memBannerText.get(comp);
  9334. Replacing.set(banner, [text$2(text)]);
  9335. }
  9336. };
  9337. const apis = {
  9338. updateProgress,
  9339. updateText
  9340. };
  9341. const iconChoices = flatten([
  9342. detail.icon.toArray(),
  9343. detail.level.toArray(),
  9344. detail.level.bind(level => Optional.from(notificationIconMap[level])).toArray()
  9345. ]);
  9346. const memButton = record(Button.sketch({
  9347. dom: {
  9348. tag: 'button',
  9349. classes: [
  9350. 'tox-notification__dismiss',
  9351. 'tox-button',
  9352. 'tox-button--naked',
  9353. 'tox-button--icon'
  9354. ]
  9355. },
  9356. components: [render$3('close', {
  9357. tag: 'span',
  9358. classes: ['tox-icon'],
  9359. attributes: { 'aria-label': detail.translationProvider('Close') }
  9360. }, detail.iconProvider)],
  9361. action: comp => {
  9362. detail.onAction(comp);
  9363. }
  9364. }));
  9365. const notificationIconSpec = renderFirst(iconChoices, {
  9366. tag: 'div',
  9367. classes: ['tox-notification__icon']
  9368. }, detail.iconProvider);
  9369. const notificationBodySpec = {
  9370. dom: {
  9371. tag: 'div',
  9372. classes: ['tox-notification__body']
  9373. },
  9374. components: [memBannerText.asSpec()],
  9375. behaviours: derive$1([Replacing.config({})])
  9376. };
  9377. const components = [
  9378. notificationIconSpec,
  9379. notificationBodySpec
  9380. ];
  9381. return {
  9382. uid: detail.uid,
  9383. dom: {
  9384. tag: 'div',
  9385. attributes: { role: 'alert' },
  9386. classes: detail.level.map(level => [
  9387. 'tox-notification',
  9388. 'tox-notification--in',
  9389. `tox-notification--${ level }`
  9390. ]).getOr([
  9391. 'tox-notification',
  9392. 'tox-notification--in'
  9393. ])
  9394. },
  9395. behaviours: derive$1([
  9396. Focusing.config({}),
  9397. config('notification-events', [run$1(focusin(), comp => {
  9398. memButton.getOpt(comp).each(Focusing.focus);
  9399. })])
  9400. ]),
  9401. components: components.concat(detail.progress ? [memBannerProgress.asSpec()] : []).concat(!detail.closeButton ? [] : [memButton.asSpec()]),
  9402. apis
  9403. };
  9404. };
  9405. const Notification = single({
  9406. name: 'Notification',
  9407. factory: factory$m,
  9408. configFields: [
  9409. option$3('level'),
  9410. required$1('progress'),
  9411. option$3('icon'),
  9412. required$1('onAction'),
  9413. required$1('text'),
  9414. required$1('iconProvider'),
  9415. required$1('translationProvider'),
  9416. defaultedBoolean('closeButton', true)
  9417. ],
  9418. apis: {
  9419. updateProgress: (apis, comp, percent) => {
  9420. apis.updateProgress(comp, percent);
  9421. },
  9422. updateText: (apis, comp, text) => {
  9423. apis.updateText(comp, text);
  9424. }
  9425. }
  9426. });
  9427. var NotificationManagerImpl = (editor, extras, uiMothership) => {
  9428. const sharedBackstage = extras.backstage.shared;
  9429. const getBounds = () => {
  9430. const contentArea = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
  9431. const win$1 = win();
  9432. const x = clamp(win$1.x, contentArea.x, contentArea.right);
  9433. const y = clamp(win$1.y, contentArea.y, contentArea.bottom);
  9434. const right = Math.max(contentArea.right, win$1.right);
  9435. const bottom = Math.max(contentArea.bottom, win$1.bottom);
  9436. return Optional.some(bounds(x, y, right - x, bottom - y));
  9437. };
  9438. const open = (settings, closeCallback) => {
  9439. const close = () => {
  9440. closeCallback();
  9441. InlineView.hide(notificationWrapper);
  9442. };
  9443. const notification = build$1(Notification.sketch({
  9444. text: settings.text,
  9445. level: contains$2([
  9446. 'success',
  9447. 'error',
  9448. 'warning',
  9449. 'warn',
  9450. 'info'
  9451. ], settings.type) ? settings.type : undefined,
  9452. progress: settings.progressBar === true,
  9453. icon: settings.icon,
  9454. closeButton: settings.closeButton,
  9455. onAction: close,
  9456. iconProvider: sharedBackstage.providers.icons,
  9457. translationProvider: sharedBackstage.providers.translate
  9458. }));
  9459. const notificationWrapper = build$1(InlineView.sketch({
  9460. dom: {
  9461. tag: 'div',
  9462. classes: ['tox-notifications-container']
  9463. },
  9464. lazySink: sharedBackstage.getSink,
  9465. fireDismissalEventInstead: {},
  9466. ...sharedBackstage.header.isPositionedAtTop() ? {} : { fireRepositionEventInstead: {} }
  9467. }));
  9468. uiMothership.add(notificationWrapper);
  9469. if (isNumber(settings.timeout) && settings.timeout > 0) {
  9470. global$9.setEditorTimeout(editor, () => {
  9471. close();
  9472. }, settings.timeout);
  9473. }
  9474. const reposition = () => {
  9475. const notificationSpec = premade(notification);
  9476. const anchorOverrides = { maxHeightFunction: expandable$1() };
  9477. const allNotifications = editor.notificationManager.getNotifications();
  9478. if (allNotifications[0] === thisNotification) {
  9479. const anchor = {
  9480. ...sharedBackstage.anchors.banner(),
  9481. overrides: anchorOverrides
  9482. };
  9483. InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor }, getBounds);
  9484. } else {
  9485. indexOf(allNotifications, thisNotification).each(idx => {
  9486. const previousNotification = allNotifications[idx - 1].getEl();
  9487. const nodeAnchor = {
  9488. type: 'node',
  9489. root: body(),
  9490. node: Optional.some(SugarElement.fromDom(previousNotification)),
  9491. overrides: anchorOverrides,
  9492. layouts: {
  9493. onRtl: () => [south$2],
  9494. onLtr: () => [south$2]
  9495. }
  9496. };
  9497. InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor: nodeAnchor }, getBounds);
  9498. });
  9499. }
  9500. };
  9501. const thisNotification = {
  9502. close,
  9503. reposition,
  9504. text: nuText => {
  9505. Notification.updateText(notification, nuText);
  9506. },
  9507. settings,
  9508. getEl: () => notification.element.dom,
  9509. progressBar: {
  9510. value: percent => {
  9511. Notification.updateProgress(notification, percent);
  9512. }
  9513. }
  9514. };
  9515. return thisNotification;
  9516. };
  9517. const close = notification => {
  9518. notification.close();
  9519. };
  9520. const getArgs = notification => {
  9521. return notification.settings;
  9522. };
  9523. return {
  9524. open,
  9525. close,
  9526. getArgs
  9527. };
  9528. };
  9529. var global$7 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  9530. var global$6 = tinymce.util.Tools.resolve('tinymce.EditorManager');
  9531. var global$5 = tinymce.util.Tools.resolve('tinymce.Env');
  9532. var ToolbarMode$1;
  9533. (function (ToolbarMode) {
  9534. ToolbarMode['default'] = 'wrap';
  9535. ToolbarMode['floating'] = 'floating';
  9536. ToolbarMode['sliding'] = 'sliding';
  9537. ToolbarMode['scrolling'] = 'scrolling';
  9538. }(ToolbarMode$1 || (ToolbarMode$1 = {})));
  9539. var ToolbarLocation$1;
  9540. (function (ToolbarLocation) {
  9541. ToolbarLocation['auto'] = 'auto';
  9542. ToolbarLocation['top'] = 'top';
  9543. ToolbarLocation['bottom'] = 'bottom';
  9544. }(ToolbarLocation$1 || (ToolbarLocation$1 = {})));
  9545. const option$2 = name => editor => editor.options.get(name);
  9546. const wrapOptional = fn => editor => Optional.from(fn(editor));
  9547. const register$e = editor => {
  9548. const isPhone = global$5.deviceType.isPhone();
  9549. const isMobile = global$5.deviceType.isTablet() || isPhone;
  9550. const registerOption = editor.options.register;
  9551. const stringOrFalseProcessor = value => isString(value) || value === false;
  9552. const stringOrNumberProcessor = value => isString(value) || isNumber(value);
  9553. registerOption('skin', {
  9554. processor: value => isString(value) || value === false,
  9555. default: 'oxide'
  9556. });
  9557. registerOption('skin_url', { processor: 'string' });
  9558. registerOption('height', {
  9559. processor: stringOrNumberProcessor,
  9560. default: Math.max(editor.getElement().offsetHeight, 400)
  9561. });
  9562. registerOption('width', {
  9563. processor: stringOrNumberProcessor,
  9564. default: global$7.DOM.getStyle(editor.getElement(), 'width')
  9565. });
  9566. registerOption('min_height', {
  9567. processor: 'number',
  9568. default: 100
  9569. });
  9570. registerOption('min_width', { processor: 'number' });
  9571. registerOption('max_height', { processor: 'number' });
  9572. registerOption('max_width', { processor: 'number' });
  9573. registerOption('style_formats', { processor: 'object[]' });
  9574. registerOption('style_formats_merge', {
  9575. processor: 'boolean',
  9576. default: false
  9577. });
  9578. registerOption('style_formats_autohide', {
  9579. processor: 'boolean',
  9580. default: false
  9581. });
  9582. registerOption('line_height_formats', {
  9583. processor: 'string',
  9584. default: '1 1.1 1.2 1.3 1.4 1.5 2'
  9585. });
  9586. registerOption('font_family_formats', {
  9587. processor: 'string',
  9588. default: 'Andale Mono=andale mono,monospace;' + 'Arial=arial,helvetica,sans-serif;' + 'Arial Black=arial black,sans-serif;' + 'Book Antiqua=book antiqua,palatino,serif;' + 'Comic Sans MS=comic sans ms,sans-serif;' + 'Courier New=courier new,courier,monospace;' + 'Georgia=georgia,palatino,serif;' + 'Helvetica=helvetica,arial,sans-serif;' + 'Impact=impact,sans-serif;' + 'Symbol=symbol;' + 'Tahoma=tahoma,arial,helvetica,sans-serif;' + 'Terminal=terminal,monaco,monospace;' + 'Times New Roman=times new roman,times,serif;' + 'Trebuchet MS=trebuchet ms,geneva,sans-serif;' + 'Verdana=verdana,geneva,sans-serif;' + 'Webdings=webdings;' + 'Wingdings=wingdings,zapf dingbats'
  9589. });
  9590. registerOption('font_size_formats', {
  9591. processor: 'string',
  9592. default: '8pt 10pt 12pt 14pt 18pt 24pt 36pt'
  9593. });
  9594. registerOption('font_size_input_default_unit', {
  9595. processor: 'string',
  9596. default: 'pt'
  9597. });
  9598. registerOption('block_formats', {
  9599. processor: 'string',
  9600. default: 'Paragraph=p;' + 'Heading 1=h1;' + 'Heading 2=h2;' + 'Heading 3=h3;' + 'Heading 4=h4;' + 'Heading 5=h5;' + 'Heading 6=h6;' + 'Preformatted=pre'
  9601. });
  9602. registerOption('content_langs', { processor: 'object[]' });
  9603. registerOption('removed_menuitems', {
  9604. processor: 'string',
  9605. default: ''
  9606. });
  9607. registerOption('menubar', {
  9608. processor: value => isString(value) || isBoolean(value),
  9609. default: !isPhone
  9610. });
  9611. registerOption('menu', {
  9612. processor: 'object',
  9613. default: {}
  9614. });
  9615. registerOption('toolbar', {
  9616. processor: value => {
  9617. if (isBoolean(value) || isString(value) || isArray(value)) {
  9618. return {
  9619. value,
  9620. valid: true
  9621. };
  9622. } else {
  9623. return {
  9624. valid: false,
  9625. message: 'Must be a boolean, string or array.'
  9626. };
  9627. }
  9628. },
  9629. default: true
  9630. });
  9631. range$2(9, num => {
  9632. registerOption('toolbar' + (num + 1), { processor: 'string' });
  9633. });
  9634. registerOption('toolbar_mode', {
  9635. processor: 'string',
  9636. default: isMobile ? 'scrolling' : 'floating'
  9637. });
  9638. registerOption('toolbar_groups', {
  9639. processor: 'object',
  9640. default: {}
  9641. });
  9642. registerOption('toolbar_location', {
  9643. processor: 'string',
  9644. default: ToolbarLocation$1.auto
  9645. });
  9646. registerOption('toolbar_persist', {
  9647. processor: 'boolean',
  9648. default: false
  9649. });
  9650. registerOption('toolbar_sticky', {
  9651. processor: 'boolean',
  9652. default: editor.inline
  9653. });
  9654. registerOption('toolbar_sticky_offset', {
  9655. processor: 'number',
  9656. default: 0
  9657. });
  9658. registerOption('fixed_toolbar_container', {
  9659. processor: 'string',
  9660. default: ''
  9661. });
  9662. registerOption('fixed_toolbar_container_target', { processor: 'object' });
  9663. registerOption('ui_mode', {
  9664. processor: 'string',
  9665. default: 'combined'
  9666. });
  9667. registerOption('file_picker_callback', { processor: 'function' });
  9668. registerOption('file_picker_validator_handler', { processor: 'function' });
  9669. registerOption('file_picker_types', { processor: 'string' });
  9670. registerOption('typeahead_urls', {
  9671. processor: 'boolean',
  9672. default: true
  9673. });
  9674. registerOption('anchor_top', {
  9675. processor: stringOrFalseProcessor,
  9676. default: '#top'
  9677. });
  9678. registerOption('anchor_bottom', {
  9679. processor: stringOrFalseProcessor,
  9680. default: '#bottom'
  9681. });
  9682. registerOption('draggable_modal', {
  9683. processor: 'boolean',
  9684. default: false
  9685. });
  9686. registerOption('statusbar', {
  9687. processor: 'boolean',
  9688. default: true
  9689. });
  9690. registerOption('elementpath', {
  9691. processor: 'boolean',
  9692. default: true
  9693. });
  9694. registerOption('branding', {
  9695. processor: 'boolean',
  9696. default: true
  9697. });
  9698. registerOption('promotion', {
  9699. processor: 'boolean',
  9700. default: true
  9701. });
  9702. registerOption('resize', {
  9703. processor: value => value === 'both' || isBoolean(value),
  9704. default: !global$5.deviceType.isTouch()
  9705. });
  9706. registerOption('sidebar_show', { processor: 'string' });
  9707. registerOption('help_accessibility', {
  9708. processor: 'boolean',
  9709. default: editor.hasPlugin('help')
  9710. });
  9711. registerOption('default_font_stack', {
  9712. processor: 'string[]',
  9713. default: []
  9714. });
  9715. };
  9716. const isReadOnly = option$2('readonly');
  9717. const getHeightOption = option$2('height');
  9718. const getWidthOption = option$2('width');
  9719. const getMinWidthOption = wrapOptional(option$2('min_width'));
  9720. const getMinHeightOption = wrapOptional(option$2('min_height'));
  9721. const getMaxWidthOption = wrapOptional(option$2('max_width'));
  9722. const getMaxHeightOption = wrapOptional(option$2('max_height'));
  9723. const getUserStyleFormats = wrapOptional(option$2('style_formats'));
  9724. const shouldMergeStyleFormats = option$2('style_formats_merge');
  9725. const shouldAutoHideStyleFormats = option$2('style_formats_autohide');
  9726. const getContentLanguages = option$2('content_langs');
  9727. const getRemovedMenuItems = option$2('removed_menuitems');
  9728. const getToolbarMode = option$2('toolbar_mode');
  9729. const getToolbarGroups = option$2('toolbar_groups');
  9730. const getToolbarLocation = option$2('toolbar_location');
  9731. const fixedContainerSelector = option$2('fixed_toolbar_container');
  9732. const fixedToolbarContainerTarget = option$2('fixed_toolbar_container_target');
  9733. const isToolbarPersist = option$2('toolbar_persist');
  9734. const getStickyToolbarOffset = option$2('toolbar_sticky_offset');
  9735. const getMenubar = option$2('menubar');
  9736. const getToolbar = option$2('toolbar');
  9737. const getFilePickerCallback = option$2('file_picker_callback');
  9738. const getFilePickerValidatorHandler = option$2('file_picker_validator_handler');
  9739. const getFontSizeInputDefaultUnit = option$2('font_size_input_default_unit');
  9740. const getFilePickerTypes = option$2('file_picker_types');
  9741. const useTypeaheadUrls = option$2('typeahead_urls');
  9742. const getAnchorTop = option$2('anchor_top');
  9743. const getAnchorBottom = option$2('anchor_bottom');
  9744. const isDraggableModal$1 = option$2('draggable_modal');
  9745. const useStatusBar = option$2('statusbar');
  9746. const useElementPath = option$2('elementpath');
  9747. const useBranding = option$2('branding');
  9748. const getResize = option$2('resize');
  9749. const getPasteAsText = option$2('paste_as_text');
  9750. const getSidebarShow = option$2('sidebar_show');
  9751. const promotionEnabled = option$2('promotion');
  9752. const useHelpAccessibility = option$2('help_accessibility');
  9753. const getDefaultFontStack = option$2('default_font_stack');
  9754. const isSkinDisabled = editor => editor.options.get('skin') === false;
  9755. const isMenubarEnabled = editor => editor.options.get('menubar') !== false;
  9756. const getSkinUrl = editor => {
  9757. const skinUrl = editor.options.get('skin_url');
  9758. if (isSkinDisabled(editor)) {
  9759. return skinUrl;
  9760. } else {
  9761. if (skinUrl) {
  9762. return editor.documentBaseURI.toAbsolute(skinUrl);
  9763. } else {
  9764. const skin = editor.options.get('skin');
  9765. return global$6.baseURL + '/skins/ui/' + skin;
  9766. }
  9767. }
  9768. };
  9769. const getSkinUrlOption = editor => Optional.from(editor.options.get('skin_url'));
  9770. const getLineHeightFormats = editor => editor.options.get('line_height_formats').split(' ');
  9771. const isToolbarEnabled = editor => {
  9772. const toolbar = getToolbar(editor);
  9773. const isToolbarString = isString(toolbar);
  9774. const isToolbarObjectArray = isArray(toolbar) && toolbar.length > 0;
  9775. return !isMultipleToolbars(editor) && (isToolbarObjectArray || isToolbarString || toolbar === true);
  9776. };
  9777. const getMultipleToolbarsOption = editor => {
  9778. const toolbars = range$2(9, num => editor.options.get('toolbar' + (num + 1)));
  9779. const toolbarArray = filter$2(toolbars, isString);
  9780. return someIf(toolbarArray.length > 0, toolbarArray);
  9781. };
  9782. const isMultipleToolbars = editor => getMultipleToolbarsOption(editor).fold(() => {
  9783. const toolbar = getToolbar(editor);
  9784. return isArrayOf(toolbar, isString) && toolbar.length > 0;
  9785. }, always);
  9786. const isToolbarLocationBottom = editor => getToolbarLocation(editor) === ToolbarLocation$1.bottom;
  9787. const fixedContainerTarget = editor => {
  9788. var _a;
  9789. if (!editor.inline) {
  9790. return Optional.none();
  9791. }
  9792. const selector = (_a = fixedContainerSelector(editor)) !== null && _a !== void 0 ? _a : '';
  9793. if (selector.length > 0) {
  9794. return descendant(body(), selector);
  9795. }
  9796. const element = fixedToolbarContainerTarget(editor);
  9797. if (isNonNullable(element)) {
  9798. return Optional.some(SugarElement.fromDom(element));
  9799. }
  9800. return Optional.none();
  9801. };
  9802. const useFixedContainer = editor => editor.inline && fixedContainerTarget(editor).isSome();
  9803. const getUiContainer = editor => {
  9804. const fixedContainer = fixedContainerTarget(editor);
  9805. return fixedContainer.getOrThunk(() => getContentContainer(getRootNode(SugarElement.fromDom(editor.getElement()))));
  9806. };
  9807. const isDistractionFree = editor => editor.inline && !isMenubarEnabled(editor) && !isToolbarEnabled(editor) && !isMultipleToolbars(editor);
  9808. const isStickyToolbar = editor => {
  9809. const isStickyToolbar = editor.options.get('toolbar_sticky');
  9810. return (isStickyToolbar || editor.inline) && !useFixedContainer(editor) && !isDistractionFree(editor);
  9811. };
  9812. const isSplitUiMode = editor => !useFixedContainer(editor) && editor.options.get('ui_mode') === 'split';
  9813. const getMenus = editor => {
  9814. const menu = editor.options.get('menu');
  9815. return map$1(menu, menu => ({
  9816. ...menu,
  9817. items: menu.items
  9818. }));
  9819. };
  9820. var Options = /*#__PURE__*/Object.freeze({
  9821. __proto__: null,
  9822. get ToolbarMode () { return ToolbarMode$1; },
  9823. get ToolbarLocation () { return ToolbarLocation$1; },
  9824. register: register$e,
  9825. getSkinUrl: getSkinUrl,
  9826. getSkinUrlOption: getSkinUrlOption,
  9827. isReadOnly: isReadOnly,
  9828. isSkinDisabled: isSkinDisabled,
  9829. getHeightOption: getHeightOption,
  9830. getWidthOption: getWidthOption,
  9831. getMinWidthOption: getMinWidthOption,
  9832. getMinHeightOption: getMinHeightOption,
  9833. getMaxWidthOption: getMaxWidthOption,
  9834. getMaxHeightOption: getMaxHeightOption,
  9835. getUserStyleFormats: getUserStyleFormats,
  9836. shouldMergeStyleFormats: shouldMergeStyleFormats,
  9837. shouldAutoHideStyleFormats: shouldAutoHideStyleFormats,
  9838. getLineHeightFormats: getLineHeightFormats,
  9839. getContentLanguages: getContentLanguages,
  9840. getRemovedMenuItems: getRemovedMenuItems,
  9841. isMenubarEnabled: isMenubarEnabled,
  9842. isMultipleToolbars: isMultipleToolbars,
  9843. isToolbarEnabled: isToolbarEnabled,
  9844. isToolbarPersist: isToolbarPersist,
  9845. getMultipleToolbarsOption: getMultipleToolbarsOption,
  9846. getUiContainer: getUiContainer,
  9847. useFixedContainer: useFixedContainer,
  9848. isSplitUiMode: isSplitUiMode,
  9849. getToolbarMode: getToolbarMode,
  9850. isDraggableModal: isDraggableModal$1,
  9851. isDistractionFree: isDistractionFree,
  9852. isStickyToolbar: isStickyToolbar,
  9853. getStickyToolbarOffset: getStickyToolbarOffset,
  9854. getToolbarLocation: getToolbarLocation,
  9855. isToolbarLocationBottom: isToolbarLocationBottom,
  9856. getToolbarGroups: getToolbarGroups,
  9857. getMenus: getMenus,
  9858. getMenubar: getMenubar,
  9859. getToolbar: getToolbar,
  9860. getFilePickerCallback: getFilePickerCallback,
  9861. getFilePickerTypes: getFilePickerTypes,
  9862. useTypeaheadUrls: useTypeaheadUrls,
  9863. getAnchorTop: getAnchorTop,
  9864. getAnchorBottom: getAnchorBottom,
  9865. getFilePickerValidatorHandler: getFilePickerValidatorHandler,
  9866. getFontSizeInputDefaultUnit: getFontSizeInputDefaultUnit,
  9867. useStatusBar: useStatusBar,
  9868. useElementPath: useElementPath,
  9869. promotionEnabled: promotionEnabled,
  9870. useBranding: useBranding,
  9871. getResize: getResize,
  9872. getPasteAsText: getPasteAsText,
  9873. getSidebarShow: getSidebarShow,
  9874. useHelpAccessibility: useHelpAccessibility,
  9875. getDefaultFontStack: getDefaultFontStack
  9876. });
  9877. const autocompleteSelector = '[data-mce-autocompleter]';
  9878. const detect$1 = elm => closest$1(elm, autocompleteSelector);
  9879. const findIn = elm => descendant(elm, autocompleteSelector);
  9880. const setup$e = (api, editor) => {
  9881. const redirectKeyToItem = (item, e) => {
  9882. emitWith(item, keydown(), { raw: e });
  9883. };
  9884. const getItem = () => api.getMenu().bind(Highlighting.getHighlighted);
  9885. editor.on('keydown', e => {
  9886. const keyCode = e.which;
  9887. if (!api.isActive()) {
  9888. return;
  9889. }
  9890. if (api.isMenuOpen()) {
  9891. if (keyCode === 13) {
  9892. getItem().each(emitExecute);
  9893. e.preventDefault();
  9894. } else if (keyCode === 40) {
  9895. getItem().fold(() => {
  9896. api.getMenu().each(Highlighting.highlightFirst);
  9897. }, item => {
  9898. redirectKeyToItem(item, e);
  9899. });
  9900. e.preventDefault();
  9901. e.stopImmediatePropagation();
  9902. } else if (keyCode === 37 || keyCode === 38 || keyCode === 39) {
  9903. getItem().each(item => {
  9904. redirectKeyToItem(item, e);
  9905. e.preventDefault();
  9906. e.stopImmediatePropagation();
  9907. });
  9908. }
  9909. } else {
  9910. if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
  9911. api.cancelIfNecessary();
  9912. }
  9913. }
  9914. });
  9915. editor.on('NodeChange', e => {
  9916. if (api.isActive() && !api.isProcessingAction() && detect$1(SugarElement.fromDom(e.element)).isNone()) {
  9917. api.cancelIfNecessary();
  9918. }
  9919. });
  9920. };
  9921. const AutocompleterEditorEvents = { setup: setup$e };
  9922. var ItemResponse;
  9923. (function (ItemResponse) {
  9924. ItemResponse[ItemResponse['CLOSE_ON_EXECUTE'] = 0] = 'CLOSE_ON_EXECUTE';
  9925. ItemResponse[ItemResponse['BUBBLE_TO_SANDBOX'] = 1] = 'BUBBLE_TO_SANDBOX';
  9926. }(ItemResponse || (ItemResponse = {})));
  9927. var ItemResponse$1 = ItemResponse;
  9928. const navClass = 'tox-menu-nav__js';
  9929. const selectableClass = 'tox-collection__item';
  9930. const colorClass = 'tox-swatch';
  9931. const presetClasses = {
  9932. normal: navClass,
  9933. color: colorClass
  9934. };
  9935. const tickedClass = 'tox-collection__item--enabled';
  9936. const groupHeadingClass = 'tox-collection__group-heading';
  9937. const iconClass = 'tox-collection__item-icon';
  9938. const textClass = 'tox-collection__item-label';
  9939. const accessoryClass = 'tox-collection__item-accessory';
  9940. const caretClass = 'tox-collection__item-caret';
  9941. const checkmarkClass = 'tox-collection__item-checkmark';
  9942. const activeClass = 'tox-collection__item--active';
  9943. const containerClass = 'tox-collection__item-container';
  9944. const containerColumnClass = 'tox-collection__item-container--column';
  9945. const containerRowClass = 'tox-collection__item-container--row';
  9946. const containerAlignRightClass = 'tox-collection__item-container--align-right';
  9947. const containerAlignLeftClass = 'tox-collection__item-container--align-left';
  9948. const containerValignTopClass = 'tox-collection__item-container--valign-top';
  9949. const containerValignMiddleClass = 'tox-collection__item-container--valign-middle';
  9950. const containerValignBottomClass = 'tox-collection__item-container--valign-bottom';
  9951. const classForPreset = presets => get$g(presetClasses, presets).getOr(navClass);
  9952. const forMenu = presets => {
  9953. if (presets === 'color') {
  9954. return 'tox-swatches';
  9955. } else {
  9956. return 'tox-menu';
  9957. }
  9958. };
  9959. const classes = presets => ({
  9960. backgroundMenu: 'tox-background-menu',
  9961. selectedMenu: 'tox-selected-menu',
  9962. selectedItem: 'tox-collection__item--active',
  9963. hasIcons: 'tox-menu--has-icons',
  9964. menu: forMenu(presets),
  9965. tieredMenu: 'tox-tiered-menu'
  9966. });
  9967. const markers = presets => {
  9968. const menuClasses = classes(presets);
  9969. return {
  9970. backgroundMenu: menuClasses.backgroundMenu,
  9971. selectedMenu: menuClasses.selectedMenu,
  9972. menu: menuClasses.menu,
  9973. selectedItem: menuClasses.selectedItem,
  9974. item: classForPreset(presets)
  9975. };
  9976. };
  9977. const dom$1 = (hasIcons, columns, presets) => {
  9978. const menuClasses = classes(presets);
  9979. return {
  9980. tag: 'div',
  9981. classes: flatten([
  9982. [
  9983. menuClasses.menu,
  9984. `tox-menu-${ columns }-column`
  9985. ],
  9986. hasIcons ? [menuClasses.hasIcons] : []
  9987. ])
  9988. };
  9989. };
  9990. const components = [Menu.parts.items({})];
  9991. const part = (hasIcons, columns, presets) => {
  9992. const menuClasses = classes(presets);
  9993. const d = {
  9994. tag: 'div',
  9995. classes: flatten([[menuClasses.tieredMenu]])
  9996. };
  9997. return {
  9998. dom: d,
  9999. markers: markers(presets)
  10000. };
  10001. };
  10002. const schema$l = constant$1([
  10003. option$3('data'),
  10004. defaulted('inputAttributes', {}),
  10005. defaulted('inputStyles', {}),
  10006. defaulted('tag', 'input'),
  10007. defaulted('inputClasses', []),
  10008. onHandler('onSetValue'),
  10009. defaulted('styles', {}),
  10010. defaulted('eventOrder', {}),
  10011. field('inputBehaviours', [
  10012. Representing,
  10013. Focusing
  10014. ]),
  10015. defaulted('selectOnFocus', true)
  10016. ]);
  10017. const focusBehaviours = detail => derive$1([Focusing.config({
  10018. onFocus: !detail.selectOnFocus ? noop : component => {
  10019. const input = component.element;
  10020. const value = get$6(input);
  10021. input.dom.setSelectionRange(0, value.length);
  10022. }
  10023. })]);
  10024. const behaviours = detail => ({
  10025. ...focusBehaviours(detail),
  10026. ...augment(detail.inputBehaviours, [Representing.config({
  10027. store: {
  10028. mode: 'manual',
  10029. ...detail.data.map(data => ({ initialValue: data })).getOr({}),
  10030. getValue: input => {
  10031. return get$6(input.element);
  10032. },
  10033. setValue: (input, data) => {
  10034. const current = get$6(input.element);
  10035. if (current !== data) {
  10036. set$5(input.element, data);
  10037. }
  10038. }
  10039. },
  10040. onSetValue: detail.onSetValue
  10041. })])
  10042. });
  10043. const dom = detail => ({
  10044. tag: detail.tag,
  10045. attributes: {
  10046. type: 'text',
  10047. ...detail.inputAttributes
  10048. },
  10049. styles: detail.inputStyles,
  10050. classes: detail.inputClasses
  10051. });
  10052. const factory$l = (detail, _spec) => ({
  10053. uid: detail.uid,
  10054. dom: dom(detail),
  10055. components: [],
  10056. behaviours: behaviours(detail),
  10057. eventOrder: detail.eventOrder
  10058. });
  10059. const Input = single({
  10060. name: 'Input',
  10061. configFields: schema$l(),
  10062. factory: factory$l
  10063. });
  10064. const refetchTriggerEvent = generate$6('refetch-trigger-event');
  10065. const redirectMenuItemInteractionEvent = generate$6('redirect-menu-item-interaction');
  10066. const menuSearcherClass = 'tox-menu__searcher';
  10067. const findWithinSandbox = sandboxComp => {
  10068. return descendant(sandboxComp.element, `.${ menuSearcherClass }`).bind(inputElem => sandboxComp.getSystem().getByDom(inputElem).toOptional());
  10069. };
  10070. const findWithinMenu = findWithinSandbox;
  10071. const restoreState = (inputComp, searcherState) => {
  10072. Representing.setValue(inputComp, searcherState.fetchPattern);
  10073. inputComp.element.dom.selectionStart = searcherState.selectionStart;
  10074. inputComp.element.dom.selectionEnd = searcherState.selectionEnd;
  10075. };
  10076. const saveState = inputComp => {
  10077. const fetchPattern = Representing.getValue(inputComp);
  10078. const selectionStart = inputComp.element.dom.selectionStart;
  10079. const selectionEnd = inputComp.element.dom.selectionEnd;
  10080. return {
  10081. fetchPattern,
  10082. selectionStart,
  10083. selectionEnd
  10084. };
  10085. };
  10086. const setActiveDescendant = (inputComp, active) => {
  10087. getOpt(active.element, 'id').each(id => set$9(inputComp.element, 'aria-activedescendant', id));
  10088. };
  10089. const renderMenuSearcher = spec => {
  10090. const handleByBrowser = (comp, se) => {
  10091. se.cut();
  10092. return Optional.none();
  10093. };
  10094. const handleByHighlightedItem = (comp, se) => {
  10095. const eventData = {
  10096. interactionEvent: se.event,
  10097. eventType: se.event.raw.type
  10098. };
  10099. emitWith(comp, redirectMenuItemInteractionEvent, eventData);
  10100. return Optional.some(true);
  10101. };
  10102. const customSearcherEventsName = 'searcher-events';
  10103. return {
  10104. dom: {
  10105. tag: 'div',
  10106. classes: [selectableClass]
  10107. },
  10108. components: [Input.sketch({
  10109. inputClasses: [
  10110. menuSearcherClass,
  10111. 'tox-textfield'
  10112. ],
  10113. inputAttributes: {
  10114. ...spec.placeholder.map(placeholder => ({ placeholder: spec.i18n(placeholder) })).getOr({}),
  10115. 'type': 'search',
  10116. 'aria-autocomplete': 'list'
  10117. },
  10118. inputBehaviours: derive$1([
  10119. config(customSearcherEventsName, [
  10120. run$1(input(), inputComp => {
  10121. emit(inputComp, refetchTriggerEvent);
  10122. }),
  10123. run$1(keydown(), (inputComp, se) => {
  10124. if (se.event.raw.key === 'Escape') {
  10125. se.stop();
  10126. }
  10127. })
  10128. ]),
  10129. Keying.config({
  10130. mode: 'special',
  10131. onLeft: handleByBrowser,
  10132. onRight: handleByBrowser,
  10133. onSpace: handleByBrowser,
  10134. onEnter: handleByHighlightedItem,
  10135. onEscape: handleByHighlightedItem,
  10136. onUp: handleByHighlightedItem,
  10137. onDown: handleByHighlightedItem
  10138. })
  10139. ]),
  10140. eventOrder: {
  10141. keydown: [
  10142. customSearcherEventsName,
  10143. Keying.name()
  10144. ]
  10145. }
  10146. })]
  10147. };
  10148. };
  10149. const searchResultsClass = 'tox-collection--results__js';
  10150. const augmentWithAria = item => {
  10151. var _a;
  10152. if (item.dom) {
  10153. return {
  10154. ...item,
  10155. dom: {
  10156. ...item.dom,
  10157. attributes: {
  10158. ...(_a = item.dom.attributes) !== null && _a !== void 0 ? _a : {},
  10159. 'id': generate$6('aria-item-search-result-id'),
  10160. 'aria-selected': 'false'
  10161. }
  10162. }
  10163. };
  10164. } else {
  10165. return item;
  10166. }
  10167. };
  10168. const chunk = (rowDom, numColumns) => items => {
  10169. const chunks = chunk$1(items, numColumns);
  10170. return map$2(chunks, c => ({
  10171. dom: rowDom,
  10172. components: c
  10173. }));
  10174. };
  10175. const forSwatch = columns => ({
  10176. dom: {
  10177. tag: 'div',
  10178. classes: [
  10179. 'tox-menu',
  10180. 'tox-swatches-menu'
  10181. ]
  10182. },
  10183. components: [{
  10184. dom: {
  10185. tag: 'div',
  10186. classes: ['tox-swatches']
  10187. },
  10188. components: [Menu.parts.items({
  10189. preprocess: columns !== 'auto' ? chunk({
  10190. tag: 'div',
  10191. classes: ['tox-swatches__row']
  10192. }, columns) : identity
  10193. })]
  10194. }]
  10195. });
  10196. const forToolbar = columns => ({
  10197. dom: {
  10198. tag: 'div',
  10199. classes: [
  10200. 'tox-menu',
  10201. 'tox-collection',
  10202. 'tox-collection--toolbar',
  10203. 'tox-collection--toolbar-lg'
  10204. ]
  10205. },
  10206. components: [Menu.parts.items({
  10207. preprocess: chunk({
  10208. tag: 'div',
  10209. classes: ['tox-collection__group']
  10210. }, columns)
  10211. })]
  10212. });
  10213. const preprocessCollection = (items, isSeparator) => {
  10214. const allSplits = [];
  10215. let currentSplit = [];
  10216. each$1(items, (item, i) => {
  10217. if (isSeparator(item, i)) {
  10218. if (currentSplit.length > 0) {
  10219. allSplits.push(currentSplit);
  10220. }
  10221. currentSplit = [];
  10222. if (has$2(item.dom, 'innerHtml') || item.components && item.components.length > 0) {
  10223. currentSplit.push(item);
  10224. }
  10225. } else {
  10226. currentSplit.push(item);
  10227. }
  10228. });
  10229. if (currentSplit.length > 0) {
  10230. allSplits.push(currentSplit);
  10231. }
  10232. return map$2(allSplits, s => ({
  10233. dom: {
  10234. tag: 'div',
  10235. classes: ['tox-collection__group']
  10236. },
  10237. components: s
  10238. }));
  10239. };
  10240. const insertItemsPlaceholder = (columns, initItems, onItem) => {
  10241. return Menu.parts.items({
  10242. preprocess: rawItems => {
  10243. const enrichedItems = map$2(rawItems, onItem);
  10244. if (columns !== 'auto' && columns > 1) {
  10245. return chunk({
  10246. tag: 'div',
  10247. classes: ['tox-collection__group']
  10248. }, columns)(enrichedItems);
  10249. } else {
  10250. return preprocessCollection(enrichedItems, (_item, i) => initItems[i].type === 'separator');
  10251. }
  10252. }
  10253. });
  10254. };
  10255. const forCollection = (columns, initItems, _hasIcons = true) => ({
  10256. dom: {
  10257. tag: 'div',
  10258. classes: [
  10259. 'tox-menu',
  10260. 'tox-collection'
  10261. ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
  10262. },
  10263. components: [insertItemsPlaceholder(columns, initItems, identity)]
  10264. });
  10265. const forCollectionWithSearchResults = (columns, initItems, _hasIcons = true) => {
  10266. const ariaControlsSearchResults = generate$6('aria-controls-search-results');
  10267. return {
  10268. dom: {
  10269. tag: 'div',
  10270. classes: [
  10271. 'tox-menu',
  10272. 'tox-collection',
  10273. searchResultsClass
  10274. ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid']),
  10275. attributes: { id: ariaControlsSearchResults }
  10276. },
  10277. components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
  10278. };
  10279. };
  10280. const forCollectionWithSearchField = (columns, initItems, searchField) => {
  10281. const ariaControlsSearchResults = generate$6('aria-controls-search-results');
  10282. return {
  10283. dom: {
  10284. tag: 'div',
  10285. classes: [
  10286. 'tox-menu',
  10287. 'tox-collection'
  10288. ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
  10289. },
  10290. components: [
  10291. renderMenuSearcher({
  10292. i18n: global$8.translate,
  10293. placeholder: searchField.placeholder
  10294. }),
  10295. {
  10296. dom: {
  10297. tag: 'div',
  10298. classes: [
  10299. ...columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'],
  10300. searchResultsClass
  10301. ],
  10302. attributes: { id: ariaControlsSearchResults }
  10303. },
  10304. components: [insertItemsPlaceholder(columns, initItems, augmentWithAria)]
  10305. }
  10306. ]
  10307. };
  10308. };
  10309. const forHorizontalCollection = (initItems, _hasIcons = true) => ({
  10310. dom: {
  10311. tag: 'div',
  10312. classes: [
  10313. 'tox-collection',
  10314. 'tox-collection--horizontal'
  10315. ]
  10316. },
  10317. components: [Menu.parts.items({ preprocess: items => preprocessCollection(items, (_item, i) => initItems[i].type === 'separator') })]
  10318. });
  10319. const menuHasIcons = xs => exists(xs, item => 'icon' in item && item.icon !== undefined);
  10320. const handleError = error => {
  10321. console.error(formatError(error));
  10322. console.log(error);
  10323. return Optional.none();
  10324. };
  10325. const createHorizontalPartialMenuWithAlloyItems = (value, _hasIcons, items, _columns, _menuLayout) => {
  10326. const structure = forHorizontalCollection(items);
  10327. return {
  10328. value,
  10329. dom: structure.dom,
  10330. components: structure.components,
  10331. items
  10332. };
  10333. };
  10334. const createPartialMenuWithAlloyItems = (value, hasIcons, items, columns, menuLayout) => {
  10335. const getNormalStructure = () => {
  10336. if (menuLayout.menuType !== 'searchable') {
  10337. return forCollection(columns, items);
  10338. } else {
  10339. return menuLayout.searchMode.searchMode === 'search-with-field' ? forCollectionWithSearchField(columns, items, menuLayout.searchMode) : forCollectionWithSearchResults(columns, items);
  10340. }
  10341. };
  10342. if (menuLayout.menuType === 'color') {
  10343. const structure = forSwatch(columns);
  10344. return {
  10345. value,
  10346. dom: structure.dom,
  10347. components: structure.components,
  10348. items
  10349. };
  10350. } else if (menuLayout.menuType === 'normal' && columns === 'auto') {
  10351. const structure = forCollection(columns, items);
  10352. return {
  10353. value,
  10354. dom: structure.dom,
  10355. components: structure.components,
  10356. items
  10357. };
  10358. } else if (menuLayout.menuType === 'normal' || menuLayout.menuType === 'searchable') {
  10359. const structure = getNormalStructure();
  10360. return {
  10361. value,
  10362. dom: structure.dom,
  10363. components: structure.components,
  10364. items
  10365. };
  10366. } else if (menuLayout.menuType === 'listpreview' && columns !== 'auto') {
  10367. const structure = forToolbar(columns);
  10368. return {
  10369. value,
  10370. dom: structure.dom,
  10371. components: structure.components,
  10372. items
  10373. };
  10374. } else {
  10375. return {
  10376. value,
  10377. dom: dom$1(hasIcons, columns, menuLayout.menuType),
  10378. components: components,
  10379. items
  10380. };
  10381. }
  10382. };
  10383. const type = requiredString('type');
  10384. const name$1 = requiredString('name');
  10385. const label = requiredString('label');
  10386. const text = requiredString('text');
  10387. const title = requiredString('title');
  10388. const icon = requiredString('icon');
  10389. const value$1 = requiredString('value');
  10390. const fetch$1 = requiredFunction('fetch');
  10391. const getSubmenuItems = requiredFunction('getSubmenuItems');
  10392. const onAction = requiredFunction('onAction');
  10393. const onItemAction = requiredFunction('onItemAction');
  10394. const onSetup = defaultedFunction('onSetup', () => noop);
  10395. const optionalName = optionString('name');
  10396. const optionalText = optionString('text');
  10397. const optionalIcon = optionString('icon');
  10398. const optionalTooltip = optionString('tooltip');
  10399. const optionalLabel = optionString('label');
  10400. const optionalShortcut = optionString('shortcut');
  10401. const optionalSelect = optionFunction('select');
  10402. const active = defaultedBoolean('active', false);
  10403. const borderless = defaultedBoolean('borderless', false);
  10404. const enabled = defaultedBoolean('enabled', true);
  10405. const primary = defaultedBoolean('primary', false);
  10406. const defaultedColumns = num => defaulted('columns', num);
  10407. const defaultedMeta = defaulted('meta', {});
  10408. const defaultedOnAction = defaultedFunction('onAction', noop);
  10409. const defaultedType = type => defaultedString('type', type);
  10410. const generatedName = namePrefix => field$1('name', 'name', defaultedThunk(() => generate$6(`${ namePrefix }-name`)), string);
  10411. const generatedValue = valuePrefix => field$1('value', 'value', defaultedThunk(() => generate$6(`${ valuePrefix }-value`)), anyValue());
  10412. const separatorMenuItemSchema = objOf([
  10413. type,
  10414. optionalText
  10415. ]);
  10416. const createSeparatorMenuItem = spec => asRaw('separatormenuitem', separatorMenuItemSchema, spec);
  10417. const autocompleterItemSchema = objOf([
  10418. defaultedType('autocompleteitem'),
  10419. active,
  10420. enabled,
  10421. defaultedMeta,
  10422. value$1,
  10423. optionalText,
  10424. optionalIcon
  10425. ]);
  10426. const createSeparatorItem = spec => asRaw('Autocompleter.Separator', separatorMenuItemSchema, spec);
  10427. const createAutocompleterItem = spec => asRaw('Autocompleter.Item', autocompleterItemSchema, spec);
  10428. const baseToolbarButtonFields = [
  10429. enabled,
  10430. optionalTooltip,
  10431. optionalIcon,
  10432. optionalText,
  10433. onSetup
  10434. ];
  10435. const toolbarButtonSchema = objOf([
  10436. type,
  10437. onAction
  10438. ].concat(baseToolbarButtonFields));
  10439. const createToolbarButton = spec => asRaw('toolbarbutton', toolbarButtonSchema, spec);
  10440. const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
  10441. const toggleButtonSchema = objOf(baseToolbarToggleButtonFields.concat([
  10442. type,
  10443. onAction
  10444. ]));
  10445. const createToggleButton = spec => asRaw('ToggleButton', toggleButtonSchema, spec);
  10446. const contextBarFields = [
  10447. defaultedFunction('predicate', never),
  10448. defaultedStringEnum('scope', 'node', [
  10449. 'node',
  10450. 'editor'
  10451. ]),
  10452. defaultedStringEnum('position', 'selection', [
  10453. 'node',
  10454. 'selection',
  10455. 'line'
  10456. ])
  10457. ];
  10458. const contextButtonFields = baseToolbarButtonFields.concat([
  10459. defaultedType('contextformbutton'),
  10460. primary,
  10461. onAction,
  10462. customField('original', identity)
  10463. ]);
  10464. const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
  10465. defaultedType('contextformbutton'),
  10466. primary,
  10467. onAction,
  10468. customField('original', identity)
  10469. ]);
  10470. const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
  10471. const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
  10472. const toggleOrNormal = choose$1('type', {
  10473. contextformbutton: contextButtonFields,
  10474. contextformtogglebutton: contextToggleButtonFields
  10475. });
  10476. const contextFormSchema = objOf([
  10477. defaultedType('contextform'),
  10478. defaultedFunction('initValue', constant$1('')),
  10479. optionalLabel,
  10480. requiredArrayOf('commands', toggleOrNormal),
  10481. optionOf('launch', choose$1('type', {
  10482. contextformbutton: launchButtonFields,
  10483. contextformtogglebutton: launchToggleButtonFields
  10484. }))
  10485. ].concat(contextBarFields));
  10486. const createContextForm = spec => asRaw('ContextForm', contextFormSchema, spec);
  10487. const contextToolbarSchema = objOf([
  10488. defaultedType('contexttoolbar'),
  10489. requiredString('items')
  10490. ].concat(contextBarFields));
  10491. const createContextToolbar = spec => asRaw('ContextToolbar', contextToolbarSchema, spec);
  10492. const cardImageFields = [
  10493. type,
  10494. requiredString('src'),
  10495. optionString('alt'),
  10496. defaultedArrayOf('classes', [], string)
  10497. ];
  10498. const cardImageSchema = objOf(cardImageFields);
  10499. const cardTextFields = [
  10500. type,
  10501. text,
  10502. optionalName,
  10503. defaultedArrayOf('classes', ['tox-collection__item-label'], string)
  10504. ];
  10505. const cardTextSchema = objOf(cardTextFields);
  10506. const itemSchema$1 = valueThunk(() => choose$2('type', {
  10507. cardimage: cardImageSchema,
  10508. cardtext: cardTextSchema,
  10509. cardcontainer: cardContainerSchema
  10510. }));
  10511. const cardContainerSchema = objOf([
  10512. type,
  10513. defaultedString('direction', 'horizontal'),
  10514. defaultedString('align', 'left'),
  10515. defaultedString('valign', 'middle'),
  10516. requiredArrayOf('items', itemSchema$1)
  10517. ]);
  10518. const commonMenuItemFields = [
  10519. enabled,
  10520. optionalText,
  10521. optionalShortcut,
  10522. generatedValue('menuitem'),
  10523. defaultedMeta
  10524. ];
  10525. const cardMenuItemSchema = objOf([
  10526. type,
  10527. optionalLabel,
  10528. requiredArrayOf('items', itemSchema$1),
  10529. onSetup,
  10530. defaultedOnAction
  10531. ].concat(commonMenuItemFields));
  10532. const createCardMenuItem = spec => asRaw('cardmenuitem', cardMenuItemSchema, spec);
  10533. const choiceMenuItemSchema = objOf([
  10534. type,
  10535. active,
  10536. optionalIcon
  10537. ].concat(commonMenuItemFields));
  10538. const createChoiceMenuItem = spec => asRaw('choicemenuitem', choiceMenuItemSchema, spec);
  10539. const baseFields = [
  10540. type,
  10541. requiredString('fancytype'),
  10542. defaultedOnAction
  10543. ];
  10544. const insertTableFields = [defaulted('initData', {})].concat(baseFields);
  10545. const colorSwatchFields = [
  10546. optionFunction('select'),
  10547. defaultedObjOf('initData', {}, [
  10548. defaultedBoolean('allowCustomColors', true),
  10549. defaultedString('storageKey', 'default'),
  10550. optionArrayOf('colors', anyValue())
  10551. ])
  10552. ].concat(baseFields);
  10553. const fancyMenuItemSchema = choose$1('fancytype', {
  10554. inserttable: insertTableFields,
  10555. colorswatch: colorSwatchFields
  10556. });
  10557. const createFancyMenuItem = spec => asRaw('fancymenuitem', fancyMenuItemSchema, spec);
  10558. const menuItemSchema = objOf([
  10559. type,
  10560. onSetup,
  10561. defaultedOnAction,
  10562. optionalIcon
  10563. ].concat(commonMenuItemFields));
  10564. const createMenuItem = spec => asRaw('menuitem', menuItemSchema, spec);
  10565. const nestedMenuItemSchema = objOf([
  10566. type,
  10567. getSubmenuItems,
  10568. onSetup,
  10569. optionalIcon
  10570. ].concat(commonMenuItemFields));
  10571. const createNestedMenuItem = spec => asRaw('nestedmenuitem', nestedMenuItemSchema, spec);
  10572. const toggleMenuItemSchema = objOf([
  10573. type,
  10574. optionalIcon,
  10575. active,
  10576. onSetup,
  10577. onAction
  10578. ].concat(commonMenuItemFields));
  10579. const createToggleMenuItem = spec => asRaw('togglemenuitem', toggleMenuItemSchema, spec);
  10580. const detectSize = (comp, margin, selectorClass) => {
  10581. const descendants$1 = descendants(comp.element, '.' + selectorClass);
  10582. if (descendants$1.length > 0) {
  10583. const columnLength = findIndex$1(descendants$1, c => {
  10584. const thisTop = c.dom.getBoundingClientRect().top;
  10585. const cTop = descendants$1[0].dom.getBoundingClientRect().top;
  10586. return Math.abs(thisTop - cTop) > margin;
  10587. }).getOr(descendants$1.length);
  10588. return Optional.some({
  10589. numColumns: columnLength,
  10590. numRows: Math.ceil(descendants$1.length / columnLength)
  10591. });
  10592. } else {
  10593. return Optional.none();
  10594. }
  10595. };
  10596. const namedEvents = (name, handlers) => derive$1([config(name, handlers)]);
  10597. const unnamedEvents = handlers => namedEvents(generate$6('unnamed-events'), handlers);
  10598. const SimpleBehaviours = {
  10599. namedEvents,
  10600. unnamedEvents
  10601. };
  10602. const ExclusivityChannel = generate$6('tooltip.exclusive');
  10603. const ShowTooltipEvent = generate$6('tooltip.show');
  10604. const HideTooltipEvent = generate$6('tooltip.hide');
  10605. const hideAllExclusive = (component, _tConfig, _tState) => {
  10606. component.getSystem().broadcastOn([ExclusivityChannel], {});
  10607. };
  10608. const setComponents = (component, tConfig, tState, specs) => {
  10609. tState.getTooltip().each(tooltip => {
  10610. if (tooltip.getSystem().isConnected()) {
  10611. Replacing.set(tooltip, specs);
  10612. }
  10613. });
  10614. };
  10615. var TooltippingApis = /*#__PURE__*/Object.freeze({
  10616. __proto__: null,
  10617. hideAllExclusive: hideAllExclusive,
  10618. setComponents: setComponents
  10619. });
  10620. const events$9 = (tooltipConfig, state) => {
  10621. const hide = comp => {
  10622. state.getTooltip().each(p => {
  10623. detach(p);
  10624. tooltipConfig.onHide(comp, p);
  10625. state.clearTooltip();
  10626. });
  10627. state.clearTimer();
  10628. };
  10629. const show = comp => {
  10630. if (!state.isShowing()) {
  10631. hideAllExclusive(comp);
  10632. const sink = tooltipConfig.lazySink(comp).getOrDie();
  10633. const popup = comp.getSystem().build({
  10634. dom: tooltipConfig.tooltipDom,
  10635. components: tooltipConfig.tooltipComponents,
  10636. events: derive$2(tooltipConfig.mode === 'normal' ? [
  10637. run$1(mouseover(), _ => {
  10638. emit(comp, ShowTooltipEvent);
  10639. }),
  10640. run$1(mouseout(), _ => {
  10641. emit(comp, HideTooltipEvent);
  10642. })
  10643. ] : []),
  10644. behaviours: derive$1([Replacing.config({})])
  10645. });
  10646. state.setTooltip(popup);
  10647. attach(sink, popup);
  10648. tooltipConfig.onShow(comp, popup);
  10649. Positioning.position(sink, popup, { anchor: tooltipConfig.anchor(comp) });
  10650. }
  10651. };
  10652. return derive$2(flatten([
  10653. [
  10654. run$1(ShowTooltipEvent, comp => {
  10655. state.resetTimer(() => {
  10656. show(comp);
  10657. }, tooltipConfig.delay);
  10658. }),
  10659. run$1(HideTooltipEvent, comp => {
  10660. state.resetTimer(() => {
  10661. hide(comp);
  10662. }, tooltipConfig.delay);
  10663. }),
  10664. run$1(receive(), (comp, message) => {
  10665. const receivingData = message;
  10666. if (!receivingData.universal) {
  10667. if (contains$2(receivingData.channels, ExclusivityChannel)) {
  10668. hide(comp);
  10669. }
  10670. }
  10671. }),
  10672. runOnDetached(comp => {
  10673. hide(comp);
  10674. })
  10675. ],
  10676. tooltipConfig.mode === 'normal' ? [
  10677. run$1(focusin(), comp => {
  10678. emit(comp, ShowTooltipEvent);
  10679. }),
  10680. run$1(postBlur(), comp => {
  10681. emit(comp, HideTooltipEvent);
  10682. }),
  10683. run$1(mouseover(), comp => {
  10684. emit(comp, ShowTooltipEvent);
  10685. }),
  10686. run$1(mouseout(), comp => {
  10687. emit(comp, HideTooltipEvent);
  10688. })
  10689. ] : [
  10690. run$1(highlight$1(), (comp, _se) => {
  10691. emit(comp, ShowTooltipEvent);
  10692. }),
  10693. run$1(dehighlight$1(), comp => {
  10694. emit(comp, HideTooltipEvent);
  10695. })
  10696. ]
  10697. ]));
  10698. };
  10699. var ActiveTooltipping = /*#__PURE__*/Object.freeze({
  10700. __proto__: null,
  10701. events: events$9
  10702. });
  10703. var TooltippingSchema = [
  10704. required$1('lazySink'),
  10705. required$1('tooltipDom'),
  10706. defaulted('exclusive', true),
  10707. defaulted('tooltipComponents', []),
  10708. defaulted('delay', 300),
  10709. defaultedStringEnum('mode', 'normal', [
  10710. 'normal',
  10711. 'follow-highlight'
  10712. ]),
  10713. defaulted('anchor', comp => ({
  10714. type: 'hotspot',
  10715. hotspot: comp,
  10716. layouts: {
  10717. onLtr: constant$1([
  10718. south$2,
  10719. north$2,
  10720. southeast$2,
  10721. northeast$2,
  10722. southwest$2,
  10723. northwest$2
  10724. ]),
  10725. onRtl: constant$1([
  10726. south$2,
  10727. north$2,
  10728. southeast$2,
  10729. northeast$2,
  10730. southwest$2,
  10731. northwest$2
  10732. ])
  10733. }
  10734. })),
  10735. onHandler('onHide'),
  10736. onHandler('onShow')
  10737. ];
  10738. const init$b = () => {
  10739. const timer = value$2();
  10740. const popup = value$2();
  10741. const clearTimer = () => {
  10742. timer.on(clearTimeout);
  10743. };
  10744. const resetTimer = (f, delay) => {
  10745. clearTimer();
  10746. timer.set(setTimeout(f, delay));
  10747. };
  10748. const readState = constant$1('not-implemented');
  10749. return nu$8({
  10750. getTooltip: popup.get,
  10751. isShowing: popup.isSet,
  10752. setTooltip: popup.set,
  10753. clearTooltip: popup.clear,
  10754. clearTimer,
  10755. resetTimer,
  10756. readState
  10757. });
  10758. };
  10759. var TooltippingState = /*#__PURE__*/Object.freeze({
  10760. __proto__: null,
  10761. init: init$b
  10762. });
  10763. const Tooltipping = create$4({
  10764. fields: TooltippingSchema,
  10765. name: 'tooltipping',
  10766. active: ActiveTooltipping,
  10767. state: TooltippingState,
  10768. apis: TooltippingApis
  10769. });
  10770. const escape = text => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  10771. const ReadOnlyChannel = 'silver.readonly';
  10772. const ReadOnlyDataSchema = objOf([requiredBoolean('readonly')]);
  10773. const broadcastReadonly = (uiRefs, readonly) => {
  10774. const outerContainer = uiRefs.mainUi.outerContainer;
  10775. const target = outerContainer.element;
  10776. const motherships = [
  10777. uiRefs.mainUi.mothership,
  10778. ...uiRefs.uiMotherships
  10779. ];
  10780. if (readonly) {
  10781. each$1(motherships, m => {
  10782. m.broadcastOn([dismissPopups()], { target });
  10783. });
  10784. }
  10785. each$1(motherships, m => {
  10786. m.broadcastOn([ReadOnlyChannel], { readonly });
  10787. });
  10788. };
  10789. const setupReadonlyModeSwitch = (editor, uiRefs) => {
  10790. editor.on('init', () => {
  10791. if (editor.mode.isReadOnly()) {
  10792. broadcastReadonly(uiRefs, true);
  10793. }
  10794. });
  10795. editor.on('SwitchMode', () => broadcastReadonly(uiRefs, editor.mode.isReadOnly()));
  10796. if (isReadOnly(editor)) {
  10797. editor.mode.set('readonly');
  10798. }
  10799. };
  10800. const receivingConfig = () => Receiving.config({
  10801. channels: {
  10802. [ReadOnlyChannel]: {
  10803. schema: ReadOnlyDataSchema,
  10804. onReceive: (comp, data) => {
  10805. Disabling.set(comp, data.readonly);
  10806. }
  10807. }
  10808. }
  10809. });
  10810. const item = disabled => Disabling.config({
  10811. disabled,
  10812. disableClass: 'tox-collection__item--state-disabled'
  10813. });
  10814. const button = disabled => Disabling.config({ disabled });
  10815. const splitButton = disabled => Disabling.config({
  10816. disabled,
  10817. disableClass: 'tox-tbtn--disabled'
  10818. });
  10819. const toolbarButton = disabled => Disabling.config({
  10820. disabled,
  10821. disableClass: 'tox-tbtn--disabled',
  10822. useNative: false
  10823. });
  10824. const DisablingConfigs = {
  10825. item,
  10826. button,
  10827. splitButton,
  10828. toolbarButton
  10829. };
  10830. const runWithApi = (info, comp) => {
  10831. const api = info.getApi(comp);
  10832. return f => {
  10833. f(api);
  10834. };
  10835. };
  10836. const onControlAttached = (info, editorOffCell) => runOnAttached(comp => {
  10837. const run = runWithApi(info, comp);
  10838. run(api => {
  10839. const onDestroy = info.onSetup(api);
  10840. if (isFunction(onDestroy)) {
  10841. editorOffCell.set(onDestroy);
  10842. }
  10843. });
  10844. });
  10845. const onControlDetached = (getApi, editorOffCell) => runOnDetached(comp => runWithApi(getApi, comp)(editorOffCell.get()));
  10846. const onMenuItemExecute = (info, itemResponse) => runOnExecute$1((comp, simulatedEvent) => {
  10847. runWithApi(info, comp)(info.onAction);
  10848. if (!info.triggersSubmenu && itemResponse === ItemResponse$1.CLOSE_ON_EXECUTE) {
  10849. if (comp.getSystem().isConnected()) {
  10850. emit(comp, sandboxClose());
  10851. }
  10852. simulatedEvent.stop();
  10853. }
  10854. });
  10855. const menuItemEventOrder = {
  10856. [execute$5()]: [
  10857. 'disabling',
  10858. 'alloy.base.behaviour',
  10859. 'toggling',
  10860. 'item-events'
  10861. ]
  10862. };
  10863. const componentRenderPipeline = cat;
  10864. const renderCommonItem = (spec, structure, itemResponse, providersBackstage) => {
  10865. const editorOffCell = Cell(noop);
  10866. return {
  10867. type: 'item',
  10868. dom: structure.dom,
  10869. components: componentRenderPipeline(structure.optComponents),
  10870. data: spec.data,
  10871. eventOrder: menuItemEventOrder,
  10872. hasSubmenu: spec.triggersSubmenu,
  10873. itemBehaviours: derive$1([
  10874. config('item-events', [
  10875. onMenuItemExecute(spec, itemResponse),
  10876. onControlAttached(spec, editorOffCell),
  10877. onControlDetached(spec, editorOffCell)
  10878. ]),
  10879. DisablingConfigs.item(() => !spec.enabled || providersBackstage.isDisabled()),
  10880. receivingConfig(),
  10881. Replacing.config({})
  10882. ].concat(spec.itemBehaviours))
  10883. };
  10884. };
  10885. const buildData = source => ({
  10886. value: source.value,
  10887. meta: {
  10888. text: source.text.getOr(''),
  10889. ...source.meta
  10890. }
  10891. });
  10892. const convertText = source => {
  10893. const isMac = global$5.os.isMacOS() || global$5.os.isiOS();
  10894. const mac = {
  10895. alt: '\u2325',
  10896. ctrl: '\u2303',
  10897. shift: '\u21E7',
  10898. meta: '\u2318',
  10899. access: '\u2303\u2325'
  10900. };
  10901. const other = {
  10902. meta: 'Ctrl',
  10903. access: 'Shift+Alt'
  10904. };
  10905. const replace = isMac ? mac : other;
  10906. const shortcut = source.split('+');
  10907. const updated = map$2(shortcut, segment => {
  10908. const search = segment.toLowerCase().trim();
  10909. return has$2(replace, search) ? replace[search] : segment;
  10910. });
  10911. return isMac ? updated.join('') : updated.join('+');
  10912. };
  10913. const renderIcon$2 = (name, icons, classes = [iconClass]) => render$3(name, {
  10914. tag: 'div',
  10915. classes
  10916. }, icons);
  10917. const renderText = text => ({
  10918. dom: {
  10919. tag: 'div',
  10920. classes: [textClass]
  10921. },
  10922. components: [text$2(global$8.translate(text))]
  10923. });
  10924. const renderHtml = (html, classes) => ({
  10925. dom: {
  10926. tag: 'div',
  10927. classes,
  10928. innerHtml: html
  10929. }
  10930. });
  10931. const renderStyledText = (style, text) => ({
  10932. dom: {
  10933. tag: 'div',
  10934. classes: [textClass]
  10935. },
  10936. components: [{
  10937. dom: {
  10938. tag: style.tag,
  10939. styles: style.styles
  10940. },
  10941. components: [text$2(global$8.translate(text))]
  10942. }]
  10943. });
  10944. const renderShortcut = shortcut => ({
  10945. dom: {
  10946. tag: 'div',
  10947. classes: [accessoryClass]
  10948. },
  10949. components: [text$2(convertText(shortcut))]
  10950. });
  10951. const renderCheckmark = icons => renderIcon$2('checkmark', icons, [checkmarkClass]);
  10952. const renderSubmenuCaret = icons => renderIcon$2('chevron-right', icons, [caretClass]);
  10953. const renderDownwardsCaret = icons => renderIcon$2('chevron-down', icons, [caretClass]);
  10954. const renderContainer = (container, components) => {
  10955. const directionClass = container.direction === 'vertical' ? containerColumnClass : containerRowClass;
  10956. const alignClass = container.align === 'left' ? containerAlignLeftClass : containerAlignRightClass;
  10957. const getValignClass = () => {
  10958. switch (container.valign) {
  10959. case 'top':
  10960. return containerValignTopClass;
  10961. case 'middle':
  10962. return containerValignMiddleClass;
  10963. case 'bottom':
  10964. return containerValignBottomClass;
  10965. }
  10966. };
  10967. return {
  10968. dom: {
  10969. tag: 'div',
  10970. classes: [
  10971. containerClass,
  10972. directionClass,
  10973. alignClass,
  10974. getValignClass()
  10975. ]
  10976. },
  10977. components
  10978. };
  10979. };
  10980. const renderImage = (src, classes, alt) => ({
  10981. dom: {
  10982. tag: 'img',
  10983. classes,
  10984. attributes: {
  10985. src,
  10986. alt: alt.getOr('')
  10987. }
  10988. }
  10989. });
  10990. const renderColorStructure = (item, providerBackstage, fallbackIcon) => {
  10991. const colorPickerCommand = 'custom';
  10992. const removeColorCommand = 'remove';
  10993. const itemText = item.ariaLabel;
  10994. const itemValue = item.value;
  10995. const iconSvg = item.iconContent.map(name => getOr(name, providerBackstage.icons, fallbackIcon));
  10996. const getDom = () => {
  10997. const common = colorClass;
  10998. const icon = iconSvg.getOr('');
  10999. const attributes = itemText.map(text => ({ title: providerBackstage.translate(text) })).getOr({});
  11000. const baseDom = {
  11001. tag: 'div',
  11002. attributes,
  11003. classes: [common]
  11004. };
  11005. if (itemValue === colorPickerCommand) {
  11006. return {
  11007. ...baseDom,
  11008. tag: 'button',
  11009. classes: [
  11010. ...baseDom.classes,
  11011. 'tox-swatches__picker-btn'
  11012. ],
  11013. innerHtml: icon
  11014. };
  11015. } else if (itemValue === removeColorCommand) {
  11016. return {
  11017. ...baseDom,
  11018. classes: [
  11019. ...baseDom.classes,
  11020. 'tox-swatch--remove'
  11021. ],
  11022. innerHtml: icon
  11023. };
  11024. } else if (isNonNullable(itemValue)) {
  11025. return {
  11026. ...baseDom,
  11027. attributes: {
  11028. ...baseDom.attributes,
  11029. 'data-mce-color': itemValue
  11030. },
  11031. styles: { 'background-color': itemValue },
  11032. innerHtml: icon
  11033. };
  11034. } else {
  11035. return baseDom;
  11036. }
  11037. };
  11038. return {
  11039. dom: getDom(),
  11040. optComponents: []
  11041. };
  11042. };
  11043. const renderItemDomStructure = ariaLabel => {
  11044. const domTitle = ariaLabel.map(label => ({
  11045. attributes: {
  11046. title: global$8.translate(label),
  11047. id: generate$6('menu-item')
  11048. }
  11049. })).getOr({});
  11050. return {
  11051. tag: 'div',
  11052. classes: [
  11053. navClass,
  11054. selectableClass
  11055. ],
  11056. ...domTitle
  11057. };
  11058. };
  11059. const renderNormalItemStructure = (info, providersBackstage, renderIcons, fallbackIcon) => {
  11060. const iconSpec = {
  11061. tag: 'div',
  11062. classes: [iconClass]
  11063. };
  11064. const renderIcon = iconName => render$3(iconName, iconSpec, providersBackstage.icons, fallbackIcon);
  11065. const renderEmptyIcon = () => Optional.some({ dom: iconSpec });
  11066. const leftIcon = renderIcons ? info.iconContent.map(renderIcon).orThunk(renderEmptyIcon) : Optional.none();
  11067. const checkmark = info.checkMark;
  11068. const textRender = Optional.from(info.meta).fold(() => renderText, meta => has$2(meta, 'style') ? curry(renderStyledText, meta.style) : renderText);
  11069. const content = info.htmlContent.fold(() => info.textContent.map(textRender), html => Optional.some(renderHtml(html, [textClass])));
  11070. const menuItem = {
  11071. dom: renderItemDomStructure(info.ariaLabel),
  11072. optComponents: [
  11073. leftIcon,
  11074. content,
  11075. info.shortcutContent.map(renderShortcut),
  11076. checkmark,
  11077. info.caret
  11078. ]
  11079. };
  11080. return menuItem;
  11081. };
  11082. const renderItemStructure = (info, providersBackstage, renderIcons, fallbackIcon = Optional.none()) => {
  11083. if (info.presets === 'color') {
  11084. return renderColorStructure(info, providersBackstage, fallbackIcon);
  11085. } else {
  11086. return renderNormalItemStructure(info, providersBackstage, renderIcons, fallbackIcon);
  11087. }
  11088. };
  11089. const tooltipBehaviour = (meta, sharedBackstage) => get$g(meta, 'tooltipWorker').map(tooltipWorker => [Tooltipping.config({
  11090. lazySink: sharedBackstage.getSink,
  11091. tooltipDom: {
  11092. tag: 'div',
  11093. classes: ['tox-tooltip-worker-container']
  11094. },
  11095. tooltipComponents: [],
  11096. anchor: comp => ({
  11097. type: 'submenu',
  11098. item: comp,
  11099. overrides: { maxHeightFunction: expandable$1 }
  11100. }),
  11101. mode: 'follow-highlight',
  11102. onShow: (component, _tooltip) => {
  11103. tooltipWorker(elm => {
  11104. Tooltipping.setComponents(component, [external$1({ element: SugarElement.fromDom(elm) })]);
  11105. });
  11106. }
  11107. })]).getOr([]);
  11108. const encodeText = text => global$7.DOM.encode(text);
  11109. const replaceText = (text, matchText) => {
  11110. const translated = global$8.translate(text);
  11111. const encoded = encodeText(translated);
  11112. if (matchText.length > 0) {
  11113. const escapedMatchRegex = new RegExp(escape(matchText), 'gi');
  11114. return encoded.replace(escapedMatchRegex, match => `<span class="tox-autocompleter-highlight">${ match }</span>`);
  11115. } else {
  11116. return encoded;
  11117. }
  11118. };
  11119. const renderAutocompleteItem = (spec, matchText, useText, presets, onItemValueHandler, itemResponse, sharedBackstage, renderIcons = true) => {
  11120. const structure = renderItemStructure({
  11121. presets,
  11122. textContent: Optional.none(),
  11123. htmlContent: useText ? spec.text.map(text => replaceText(text, matchText)) : Optional.none(),
  11124. ariaLabel: spec.text,
  11125. iconContent: spec.icon,
  11126. shortcutContent: Optional.none(),
  11127. checkMark: Optional.none(),
  11128. caret: Optional.none(),
  11129. value: spec.value
  11130. }, sharedBackstage.providers, renderIcons, spec.icon);
  11131. return renderCommonItem({
  11132. data: buildData(spec),
  11133. enabled: spec.enabled,
  11134. getApi: constant$1({}),
  11135. onAction: _api => onItemValueHandler(spec.value, spec.meta),
  11136. onSetup: constant$1(noop),
  11137. triggersSubmenu: false,
  11138. itemBehaviours: tooltipBehaviour(spec.meta, sharedBackstage)
  11139. }, structure, itemResponse, sharedBackstage.providers);
  11140. };
  11141. const render$2 = (items, extras) => map$2(items, item => {
  11142. switch (item.type) {
  11143. case 'cardcontainer':
  11144. return renderContainer(item, render$2(item.items, extras));
  11145. case 'cardimage':
  11146. return renderImage(item.src, item.classes, item.alt);
  11147. case 'cardtext':
  11148. const shouldHighlight = item.name.exists(name => contains$2(extras.cardText.highlightOn, name));
  11149. const matchText = shouldHighlight ? Optional.from(extras.cardText.matchText).getOr('') : '';
  11150. return renderHtml(replaceText(item.text, matchText), item.classes);
  11151. }
  11152. });
  11153. const renderCardMenuItem = (spec, itemResponse, sharedBackstage, extras) => {
  11154. const getApi = component => ({
  11155. isEnabled: () => !Disabling.isDisabled(component),
  11156. setEnabled: state => {
  11157. Disabling.set(component, !state);
  11158. each$1(descendants(component.element, '*'), elm => {
  11159. component.getSystem().getByDom(elm).each(comp => {
  11160. if (comp.hasConfigured(Disabling)) {
  11161. Disabling.set(comp, !state);
  11162. }
  11163. });
  11164. });
  11165. }
  11166. });
  11167. const structure = {
  11168. dom: renderItemDomStructure(spec.label),
  11169. optComponents: [Optional.some({
  11170. dom: {
  11171. tag: 'div',
  11172. classes: [
  11173. containerClass,
  11174. containerRowClass
  11175. ]
  11176. },
  11177. components: render$2(spec.items, extras)
  11178. })]
  11179. };
  11180. return renderCommonItem({
  11181. data: buildData({
  11182. text: Optional.none(),
  11183. ...spec
  11184. }),
  11185. enabled: spec.enabled,
  11186. getApi,
  11187. onAction: spec.onAction,
  11188. onSetup: spec.onSetup,
  11189. triggersSubmenu: false,
  11190. itemBehaviours: Optional.from(extras.itemBehaviours).getOr([])
  11191. }, structure, itemResponse, sharedBackstage.providers);
  11192. };
  11193. const renderChoiceItem = (spec, useText, presets, onItemValueHandler, isSelected, itemResponse, providersBackstage, renderIcons = true) => {
  11194. const getApi = component => ({
  11195. setActive: state => {
  11196. Toggling.set(component, state);
  11197. },
  11198. isActive: () => Toggling.isOn(component),
  11199. isEnabled: () => !Disabling.isDisabled(component),
  11200. setEnabled: state => Disabling.set(component, !state)
  11201. });
  11202. const structure = renderItemStructure({
  11203. presets,
  11204. textContent: useText ? spec.text : Optional.none(),
  11205. htmlContent: Optional.none(),
  11206. ariaLabel: spec.text,
  11207. iconContent: spec.icon,
  11208. shortcutContent: useText ? spec.shortcut : Optional.none(),
  11209. checkMark: useText ? Optional.some(renderCheckmark(providersBackstage.icons)) : Optional.none(),
  11210. caret: Optional.none(),
  11211. value: spec.value
  11212. }, providersBackstage, renderIcons);
  11213. return deepMerge(renderCommonItem({
  11214. data: buildData(spec),
  11215. enabled: spec.enabled,
  11216. getApi,
  11217. onAction: _api => onItemValueHandler(spec.value),
  11218. onSetup: api => {
  11219. api.setActive(isSelected);
  11220. return noop;
  11221. },
  11222. triggersSubmenu: false,
  11223. itemBehaviours: []
  11224. }, structure, itemResponse, providersBackstage), {
  11225. toggling: {
  11226. toggleClass: tickedClass,
  11227. toggleOnExecute: false,
  11228. selected: spec.active,
  11229. exclusive: true
  11230. }
  11231. });
  11232. };
  11233. const parts$f = generate$3(owner$2(), parts$h());
  11234. const hexColour = value => ({ value: normalizeHex(value) });
  11235. const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  11236. const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  11237. const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
  11238. const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
  11239. const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
  11240. const getLongForm = hex => {
  11241. const hexString = hex.value.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
  11242. return { value: hexString };
  11243. };
  11244. const extractValues = hex => {
  11245. const longForm = getLongForm(hex);
  11246. const splitForm = longformRegex.exec(longForm.value);
  11247. return splitForm === null ? [
  11248. 'FFFFFF',
  11249. 'FF',
  11250. 'FF',
  11251. 'FF'
  11252. ] : splitForm;
  11253. };
  11254. const toHex = component => {
  11255. const hex = component.toString(16);
  11256. return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
  11257. };
  11258. const fromRgba = rgbaColour => {
  11259. const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
  11260. return hexColour(value);
  11261. };
  11262. const min = Math.min;
  11263. const max = Math.max;
  11264. const round$1 = Math.round;
  11265. const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  11266. const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  11267. const rgbaColour = (red, green, blue, alpha) => ({
  11268. red,
  11269. green,
  11270. blue,
  11271. alpha
  11272. });
  11273. const isRgbaComponent = value => {
  11274. const num = parseInt(value, 10);
  11275. return num.toString() === value && num >= 0 && num <= 255;
  11276. };
  11277. const fromHsv = hsv => {
  11278. let r;
  11279. let g;
  11280. let b;
  11281. const hue = (hsv.hue || 0) % 360;
  11282. let saturation = hsv.saturation / 100;
  11283. let brightness = hsv.value / 100;
  11284. saturation = max(0, min(saturation, 1));
  11285. brightness = max(0, min(brightness, 1));
  11286. if (saturation === 0) {
  11287. r = g = b = round$1(255 * brightness);
  11288. return rgbaColour(r, g, b, 1);
  11289. }
  11290. const side = hue / 60;
  11291. const chroma = brightness * saturation;
  11292. const x = chroma * (1 - Math.abs(side % 2 - 1));
  11293. const match = brightness - chroma;
  11294. switch (Math.floor(side)) {
  11295. case 0:
  11296. r = chroma;
  11297. g = x;
  11298. b = 0;
  11299. break;
  11300. case 1:
  11301. r = x;
  11302. g = chroma;
  11303. b = 0;
  11304. break;
  11305. case 2:
  11306. r = 0;
  11307. g = chroma;
  11308. b = x;
  11309. break;
  11310. case 3:
  11311. r = 0;
  11312. g = x;
  11313. b = chroma;
  11314. break;
  11315. case 4:
  11316. r = x;
  11317. g = 0;
  11318. b = chroma;
  11319. break;
  11320. case 5:
  11321. r = chroma;
  11322. g = 0;
  11323. b = x;
  11324. break;
  11325. default:
  11326. r = g = b = 0;
  11327. }
  11328. r = round$1(255 * (r + match));
  11329. g = round$1(255 * (g + match));
  11330. b = round$1(255 * (b + match));
  11331. return rgbaColour(r, g, b, 1);
  11332. };
  11333. const fromHex = hexColour => {
  11334. const result = extractValues(hexColour);
  11335. const red = parseInt(result[1], 16);
  11336. const green = parseInt(result[2], 16);
  11337. const blue = parseInt(result[3], 16);
  11338. return rgbaColour(red, green, blue, 1);
  11339. };
  11340. const fromStringValues = (red, green, blue, alpha) => {
  11341. const r = parseInt(red, 10);
  11342. const g = parseInt(green, 10);
  11343. const b = parseInt(blue, 10);
  11344. const a = parseFloat(alpha);
  11345. return rgbaColour(r, g, b, a);
  11346. };
  11347. const fromString = rgbaString => {
  11348. if (rgbaString === 'transparent') {
  11349. return Optional.some(rgbaColour(0, 0, 0, 0));
  11350. }
  11351. const rgbMatch = rgbRegex.exec(rgbaString);
  11352. if (rgbMatch !== null) {
  11353. return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
  11354. }
  11355. const rgbaMatch = rgbaRegex.exec(rgbaString);
  11356. if (rgbaMatch !== null) {
  11357. return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
  11358. }
  11359. return Optional.none();
  11360. };
  11361. const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
  11362. const red = rgbaColour(255, 0, 0, 1);
  11363. const fireSkinLoaded$1 = editor => {
  11364. editor.dispatch('SkinLoaded');
  11365. };
  11366. const fireSkinLoadError$1 = (editor, error) => {
  11367. editor.dispatch('SkinLoadError', error);
  11368. };
  11369. const fireResizeEditor = editor => {
  11370. editor.dispatch('ResizeEditor');
  11371. };
  11372. const fireResizeContent = (editor, e) => {
  11373. editor.dispatch('ResizeContent', e);
  11374. };
  11375. const fireScrollContent = (editor, e) => {
  11376. editor.dispatch('ScrollContent', e);
  11377. };
  11378. const fireTextColorChange = (editor, data) => {
  11379. editor.dispatch('TextColorChange', data);
  11380. };
  11381. const fireAfterProgressState = (editor, state) => {
  11382. editor.dispatch('AfterProgressState', { state });
  11383. };
  11384. const fireResolveName = (editor, node) => editor.dispatch('ResolveName', {
  11385. name: node.nodeName.toLowerCase(),
  11386. target: node
  11387. });
  11388. const fireToggleToolbarDrawer = (editor, state) => {
  11389. editor.dispatch('ToggleToolbarDrawer', { state });
  11390. };
  11391. const fireStylesTextUpdate = (editor, data) => {
  11392. editor.dispatch('StylesTextUpdate', data);
  11393. };
  11394. const fireAlignTextUpdate = (editor, data) => {
  11395. editor.dispatch('AlignTextUpdate', data);
  11396. };
  11397. const fireFontSizeTextUpdate = (editor, data) => {
  11398. editor.dispatch('FontSizeTextUpdate', data);
  11399. };
  11400. const fireFontSizeInputTextUpdate = (editor, data) => {
  11401. editor.dispatch('FontSizeInputTextUpdate', data);
  11402. };
  11403. const fireBlocksTextUpdate = (editor, data) => {
  11404. editor.dispatch('BlocksTextUpdate', data);
  11405. };
  11406. const fireFontFamilyTextUpdate = (editor, data) => {
  11407. editor.dispatch('FontFamilyTextUpdate', data);
  11408. };
  11409. const composeUnbinders = (f, g) => () => {
  11410. f();
  11411. g();
  11412. };
  11413. const onSetupEditableToggle = editor => onSetupEvent(editor, 'NodeChange', api => {
  11414. api.setEnabled(editor.selection.isEditable());
  11415. });
  11416. const onSetupFormatToggle = (editor, name) => api => {
  11417. const boundFormatChangeCallback = unbindable();
  11418. const init = () => {
  11419. api.setActive(editor.formatter.match(name));
  11420. const binding = editor.formatter.formatChanged(name, api.setActive);
  11421. boundFormatChangeCallback.set(binding);
  11422. };
  11423. editor.initialized ? init() : editor.once('init', init);
  11424. return () => {
  11425. editor.off('init', init);
  11426. boundFormatChangeCallback.clear();
  11427. };
  11428. };
  11429. const onSetupStateToggle = (editor, name) => api => {
  11430. const unbindEditableToogle = onSetupEditableToggle(editor)(api);
  11431. const unbindFormatToggle = onSetupFormatToggle(editor, name)(api);
  11432. return () => {
  11433. unbindEditableToogle();
  11434. unbindFormatToggle();
  11435. };
  11436. };
  11437. const onSetupEvent = (editor, event, f) => api => {
  11438. const handleEvent = () => f(api);
  11439. const init = () => {
  11440. f(api);
  11441. editor.on(event, handleEvent);
  11442. };
  11443. editor.initialized ? init() : editor.once('init', init);
  11444. return () => {
  11445. editor.off('init', init);
  11446. editor.off(event, handleEvent);
  11447. };
  11448. };
  11449. const onActionToggleFormat$1 = editor => rawItem => () => {
  11450. editor.undoManager.transact(() => {
  11451. editor.focus();
  11452. editor.execCommand('mceToggleFormat', false, rawItem.format);
  11453. });
  11454. };
  11455. const onActionExecCommand = (editor, command) => () => editor.execCommand(command);
  11456. var global$4 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
  11457. const cacheStorage = {};
  11458. const ColorCache = (storageId, max = 10) => {
  11459. const storageString = global$4.getItem(storageId);
  11460. const localstorage = isString(storageString) ? JSON.parse(storageString) : [];
  11461. const prune = list => {
  11462. const diff = max - list.length;
  11463. return diff < 0 ? list.slice(0, max) : list;
  11464. };
  11465. const cache = prune(localstorage);
  11466. const add = key => {
  11467. indexOf(cache, key).each(remove);
  11468. cache.unshift(key);
  11469. if (cache.length > max) {
  11470. cache.pop();
  11471. }
  11472. global$4.setItem(storageId, JSON.stringify(cache));
  11473. };
  11474. const remove = idx => {
  11475. cache.splice(idx, 1);
  11476. };
  11477. const state = () => cache.slice(0);
  11478. return {
  11479. add,
  11480. state
  11481. };
  11482. };
  11483. const getCacheForId = id => get$g(cacheStorage, id).getOrThunk(() => {
  11484. const storageId = `tinymce-custom-colors-${ id }`;
  11485. const currentData = global$4.getItem(storageId);
  11486. if (isNullable(currentData)) {
  11487. const legacyDefault = global$4.getItem('tinymce-custom-colors');
  11488. global$4.setItem(storageId, isNonNullable(legacyDefault) ? legacyDefault : '[]');
  11489. }
  11490. const storage = ColorCache(storageId, 10);
  11491. cacheStorage[id] = storage;
  11492. return storage;
  11493. });
  11494. const getCurrentColors = id => map$2(getCacheForId(id).state(), color => ({
  11495. type: 'choiceitem',
  11496. text: color,
  11497. icon: 'checkmark',
  11498. value: color
  11499. }));
  11500. const addColor = (id, color) => {
  11501. getCacheForId(id).add(color);
  11502. };
  11503. const hsvColour = (hue, saturation, value) => ({
  11504. hue,
  11505. saturation,
  11506. value
  11507. });
  11508. const fromRgb = rgbaColour => {
  11509. let h = 0;
  11510. let s = 0;
  11511. let v = 0;
  11512. const r = rgbaColour.red / 255;
  11513. const g = rgbaColour.green / 255;
  11514. const b = rgbaColour.blue / 255;
  11515. const minRGB = Math.min(r, Math.min(g, b));
  11516. const maxRGB = Math.max(r, Math.max(g, b));
  11517. if (minRGB === maxRGB) {
  11518. v = minRGB;
  11519. return hsvColour(0, 0, v * 100);
  11520. }
  11521. const d = r === minRGB ? g - b : b === minRGB ? r - g : b - r;
  11522. h = r === minRGB ? 3 : b === minRGB ? 1 : 5;
  11523. h = 60 * (h - d / (maxRGB - minRGB));
  11524. s = (maxRGB - minRGB) / maxRGB;
  11525. v = maxRGB;
  11526. return hsvColour(Math.round(h), Math.round(s * 100), Math.round(v * 100));
  11527. };
  11528. const hexToHsv = hex => fromRgb(fromHex(hex));
  11529. const hsvToHex = hsv => fromRgba(fromHsv(hsv));
  11530. const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
  11531. const canvas = document.createElement('canvas');
  11532. canvas.height = 1;
  11533. canvas.width = 1;
  11534. const canvasContext = canvas.getContext('2d');
  11535. canvasContext.clearRect(0, 0, canvas.width, canvas.height);
  11536. canvasContext.fillStyle = '#FFFFFF';
  11537. canvasContext.fillStyle = color;
  11538. canvasContext.fillRect(0, 0, 1, 1);
  11539. const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
  11540. const r = rgba[0];
  11541. const g = rgba[1];
  11542. const b = rgba[2];
  11543. const a = rgba[3];
  11544. return fromRgba(rgbaColour(r, g, b, a));
  11545. });
  11546. const foregroundId = 'forecolor';
  11547. const backgroundId = 'hilitecolor';
  11548. const fallbackCols = 5;
  11549. const mapColors = colorMap => {
  11550. const colors = [];
  11551. for (let i = 0; i < colorMap.length; i += 2) {
  11552. colors.push({
  11553. text: colorMap[i + 1],
  11554. value: '#' + anyToHex(colorMap[i]).value,
  11555. icon: 'checkmark',
  11556. type: 'choiceitem'
  11557. });
  11558. }
  11559. return colors;
  11560. };
  11561. const option$1 = name => editor => editor.options.get(name);
  11562. const fallbackColor = '#000000';
  11563. const register$d = editor => {
  11564. const registerOption = editor.options.register;
  11565. const colorProcessor = value => {
  11566. if (isArrayOf(value, isString)) {
  11567. return {
  11568. value: mapColors(value),
  11569. valid: true
  11570. };
  11571. } else {
  11572. return {
  11573. valid: false,
  11574. message: 'Must be an array of strings.'
  11575. };
  11576. }
  11577. };
  11578. const colorColsProcessor = value => {
  11579. if (isNumber(value) && value > 0) {
  11580. return {
  11581. value,
  11582. valid: true
  11583. };
  11584. } else {
  11585. return {
  11586. valid: false,
  11587. message: 'Must be a positive number.'
  11588. };
  11589. }
  11590. };
  11591. registerOption('color_map', {
  11592. processor: colorProcessor,
  11593. default: [
  11594. '#BFEDD2',
  11595. 'Light Green',
  11596. '#FBEEB8',
  11597. 'Light Yellow',
  11598. '#F8CAC6',
  11599. 'Light Red',
  11600. '#ECCAFA',
  11601. 'Light Purple',
  11602. '#C2E0F4',
  11603. 'Light Blue',
  11604. '#2DC26B',
  11605. 'Green',
  11606. '#F1C40F',
  11607. 'Yellow',
  11608. '#E03E2D',
  11609. 'Red',
  11610. '#B96AD9',
  11611. 'Purple',
  11612. '#3598DB',
  11613. 'Blue',
  11614. '#169179',
  11615. 'Dark Turquoise',
  11616. '#E67E23',
  11617. 'Orange',
  11618. '#BA372A',
  11619. 'Dark Red',
  11620. '#843FA1',
  11621. 'Dark Purple',
  11622. '#236FA1',
  11623. 'Dark Blue',
  11624. '#ECF0F1',
  11625. 'Light Gray',
  11626. '#CED4D9',
  11627. 'Medium Gray',
  11628. '#95A5A6',
  11629. 'Gray',
  11630. '#7E8C8D',
  11631. 'Dark Gray',
  11632. '#34495E',
  11633. 'Navy Blue',
  11634. '#000000',
  11635. 'Black',
  11636. '#ffffff',
  11637. 'White'
  11638. ]
  11639. });
  11640. registerOption('color_map_background', { processor: colorProcessor });
  11641. registerOption('color_map_foreground', { processor: colorProcessor });
  11642. registerOption('color_cols', {
  11643. processor: colorColsProcessor,
  11644. default: calcCols(editor)
  11645. });
  11646. registerOption('color_cols_foreground', {
  11647. processor: colorColsProcessor,
  11648. default: defaultCols(editor, foregroundId)
  11649. });
  11650. registerOption('color_cols_background', {
  11651. processor: colorColsProcessor,
  11652. default: defaultCols(editor, backgroundId)
  11653. });
  11654. registerOption('custom_colors', {
  11655. processor: 'boolean',
  11656. default: true
  11657. });
  11658. registerOption('color_default_foreground', {
  11659. processor: 'string',
  11660. default: fallbackColor
  11661. });
  11662. registerOption('color_default_background', {
  11663. processor: 'string',
  11664. default: fallbackColor
  11665. });
  11666. };
  11667. const getColors$2 = (editor, id) => {
  11668. if (id === foregroundId && editor.options.isSet('color_map_foreground')) {
  11669. return option$1('color_map_foreground')(editor);
  11670. } else if (id === backgroundId && editor.options.isSet('color_map_background')) {
  11671. return option$1('color_map_background')(editor);
  11672. } else {
  11673. return option$1('color_map')(editor);
  11674. }
  11675. };
  11676. const calcCols = (editor, id = 'default') => Math.max(fallbackCols, Math.ceil(Math.sqrt(getColors$2(editor, id).length)));
  11677. const defaultCols = (editor, id) => {
  11678. const defaultCols = option$1('color_cols')(editor);
  11679. const calculatedCols = calcCols(editor, id);
  11680. if (defaultCols === calcCols(editor)) {
  11681. return calculatedCols;
  11682. } else {
  11683. return defaultCols;
  11684. }
  11685. };
  11686. const getColorCols$1 = (editor, id = 'default') => {
  11687. const getCols = () => {
  11688. if (id === foregroundId) {
  11689. return option$1('color_cols_foreground')(editor);
  11690. } else if (id === backgroundId) {
  11691. return option$1('color_cols_background')(editor);
  11692. } else {
  11693. return option$1('color_cols')(editor);
  11694. }
  11695. };
  11696. return Math.round(getCols());
  11697. };
  11698. const hasCustomColors$1 = option$1('custom_colors');
  11699. const getDefaultForegroundColor = option$1('color_default_foreground');
  11700. const getDefaultBackgroundColor = option$1('color_default_background');
  11701. const defaultBackgroundColor = 'rgba(0, 0, 0, 0)';
  11702. const isValidBackgroundColor = value => fromString(value).exists(c => c.alpha !== 0);
  11703. const getClosestCssBackgroundColorValue = scope => {
  11704. return closest$4(scope, node => {
  11705. if (isElement$1(node)) {
  11706. const color = get$e(node, 'background-color');
  11707. return someIf(isValidBackgroundColor(color), color);
  11708. } else {
  11709. return Optional.none();
  11710. }
  11711. }).getOr(defaultBackgroundColor);
  11712. };
  11713. const getCurrentColor = (editor, format) => {
  11714. const node = SugarElement.fromDom(editor.selection.getStart());
  11715. const cssRgbValue = format === 'hilitecolor' ? getClosestCssBackgroundColorValue(node) : get$e(node, 'color');
  11716. return fromString(cssRgbValue).map(rgba => '#' + fromRgba(rgba).value);
  11717. };
  11718. const applyFormat = (editor, format, value) => {
  11719. editor.undoManager.transact(() => {
  11720. editor.focus();
  11721. editor.formatter.apply(format, { value });
  11722. editor.nodeChanged();
  11723. });
  11724. };
  11725. const removeFormat = (editor, format) => {
  11726. editor.undoManager.transact(() => {
  11727. editor.focus();
  11728. editor.formatter.remove(format, { value: null }, undefined, true);
  11729. editor.nodeChanged();
  11730. });
  11731. };
  11732. const registerCommands = editor => {
  11733. editor.addCommand('mceApplyTextcolor', (format, value) => {
  11734. applyFormat(editor, format, value);
  11735. });
  11736. editor.addCommand('mceRemoveTextcolor', format => {
  11737. removeFormat(editor, format);
  11738. });
  11739. };
  11740. const getAdditionalColors = hasCustom => {
  11741. const type = 'choiceitem';
  11742. const remove = {
  11743. type,
  11744. text: 'Remove color',
  11745. icon: 'color-swatch-remove-color',
  11746. value: 'remove'
  11747. };
  11748. const custom = {
  11749. type,
  11750. text: 'Custom color',
  11751. icon: 'color-picker',
  11752. value: 'custom'
  11753. };
  11754. return hasCustom ? [
  11755. remove,
  11756. custom
  11757. ] : [remove];
  11758. };
  11759. const applyColor = (editor, format, value, onChoice) => {
  11760. if (value === 'custom') {
  11761. const dialog = colorPickerDialog(editor);
  11762. dialog(colorOpt => {
  11763. colorOpt.each(color => {
  11764. addColor(format, color);
  11765. editor.execCommand('mceApplyTextcolor', format, color);
  11766. onChoice(color);
  11767. });
  11768. }, getCurrentColor(editor, format).getOr(fallbackColor));
  11769. } else if (value === 'remove') {
  11770. onChoice('');
  11771. editor.execCommand('mceRemoveTextcolor', format);
  11772. } else {
  11773. onChoice(value);
  11774. editor.execCommand('mceApplyTextcolor', format, value);
  11775. }
  11776. };
  11777. const getColors$1 = (colors, id, hasCustom) => colors.concat(getCurrentColors(id).concat(getAdditionalColors(hasCustom)));
  11778. const getFetch$1 = (colors, id, hasCustom) => callback => {
  11779. callback(getColors$1(colors, id, hasCustom));
  11780. };
  11781. const setIconColor = (splitButtonApi, name, newColor) => {
  11782. const id = name === 'forecolor' ? 'tox-icon-text-color__color' : 'tox-icon-highlight-bg-color__color';
  11783. splitButtonApi.setIconFill(id, newColor);
  11784. };
  11785. const setTooltip = (buttonApi, tooltip) => {
  11786. buttonApi.setTooltip(tooltip);
  11787. };
  11788. const select$1 = (editor, format) => value => {
  11789. const optCurrentHex = getCurrentColor(editor, format);
  11790. return is$1(optCurrentHex, value.toUpperCase());
  11791. };
  11792. const getToolTipText = (editor, format, lastColor) => {
  11793. if (isEmpty(lastColor)) {
  11794. return format === 'forecolor' ? 'Text color' : 'Background color';
  11795. }
  11796. const tooltipPrefix = format === 'forecolor' ? 'Text color {0}' : 'Background color {0}';
  11797. const colors = getColors$1(getColors$2(editor, format), format, false);
  11798. const colorText = find$5(colors, c => c.value === lastColor).getOr({ text: '' }).text;
  11799. return editor.translate([
  11800. tooltipPrefix,
  11801. editor.translate(colorText)
  11802. ]);
  11803. };
  11804. const registerTextColorButton = (editor, name, format, lastColor) => {
  11805. editor.ui.registry.addSplitButton(name, {
  11806. tooltip: getToolTipText(editor, format, lastColor.get()),
  11807. presets: 'color',
  11808. icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
  11809. select: select$1(editor, format),
  11810. columns: getColorCols$1(editor, format),
  11811. fetch: getFetch$1(getColors$2(editor, format), format, hasCustomColors$1(editor)),
  11812. onAction: _splitButtonApi => {
  11813. applyColor(editor, format, lastColor.get(), noop);
  11814. },
  11815. onItemAction: (_splitButtonApi, value) => {
  11816. applyColor(editor, format, value, newColor => {
  11817. lastColor.set(newColor);
  11818. fireTextColorChange(editor, {
  11819. name,
  11820. color: newColor
  11821. });
  11822. });
  11823. },
  11824. onSetup: splitButtonApi => {
  11825. setIconColor(splitButtonApi, name, lastColor.get());
  11826. const handler = e => {
  11827. if (e.name === name) {
  11828. setIconColor(splitButtonApi, e.name, e.color);
  11829. setTooltip(splitButtonApi, getToolTipText(editor, format, e.color));
  11830. }
  11831. };
  11832. editor.on('TextColorChange', handler);
  11833. return composeUnbinders(onSetupEditableToggle(editor)(splitButtonApi), () => {
  11834. editor.off('TextColorChange', handler);
  11835. });
  11836. }
  11837. });
  11838. };
  11839. const registerTextColorMenuItem = (editor, name, format, text, lastColor) => {
  11840. editor.ui.registry.addNestedMenuItem(name, {
  11841. text,
  11842. icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
  11843. onSetup: api => {
  11844. setTooltip(api, getToolTipText(editor, format, lastColor.get()));
  11845. setIconColor(api, name, lastColor.get());
  11846. return onSetupEditableToggle(editor)(api);
  11847. },
  11848. getSubmenuItems: () => [{
  11849. type: 'fancymenuitem',
  11850. fancytype: 'colorswatch',
  11851. select: select$1(editor, format),
  11852. initData: { storageKey: format },
  11853. onAction: data => {
  11854. applyColor(editor, format, data.value, newColor => {
  11855. lastColor.set(newColor);
  11856. fireTextColorChange(editor, {
  11857. name,
  11858. color: newColor
  11859. });
  11860. });
  11861. }
  11862. }]
  11863. });
  11864. };
  11865. const colorPickerDialog = editor => (callback, value) => {
  11866. let isValid = false;
  11867. const onSubmit = api => {
  11868. const data = api.getData();
  11869. const hex = data.colorpicker;
  11870. if (isValid) {
  11871. callback(Optional.from(hex));
  11872. api.close();
  11873. } else {
  11874. editor.windowManager.alert(editor.translate([
  11875. 'Invalid hex color code: {0}',
  11876. hex
  11877. ]));
  11878. }
  11879. };
  11880. const onAction = (_api, details) => {
  11881. if (details.name === 'hex-valid') {
  11882. isValid = details.value;
  11883. }
  11884. };
  11885. const initialData = { colorpicker: value };
  11886. editor.windowManager.open({
  11887. title: 'Color Picker',
  11888. size: 'normal',
  11889. body: {
  11890. type: 'panel',
  11891. items: [{
  11892. type: 'colorpicker',
  11893. name: 'colorpicker',
  11894. label: 'Color'
  11895. }]
  11896. },
  11897. buttons: [
  11898. {
  11899. type: 'cancel',
  11900. name: 'cancel',
  11901. text: 'Cancel'
  11902. },
  11903. {
  11904. type: 'submit',
  11905. name: 'save',
  11906. text: 'Save',
  11907. primary: true
  11908. }
  11909. ],
  11910. initialData,
  11911. onAction,
  11912. onSubmit,
  11913. onClose: noop,
  11914. onCancel: () => {
  11915. callback(Optional.none());
  11916. }
  11917. });
  11918. };
  11919. const register$c = editor => {
  11920. registerCommands(editor);
  11921. const fallbackColorForeground = getDefaultForegroundColor(editor);
  11922. const fallbackColorBackground = getDefaultBackgroundColor(editor);
  11923. const lastForeColor = Cell(fallbackColorForeground);
  11924. const lastBackColor = Cell(fallbackColorBackground);
  11925. registerTextColorButton(editor, 'forecolor', 'forecolor', lastForeColor);
  11926. registerTextColorButton(editor, 'backcolor', 'hilitecolor', lastBackColor);
  11927. registerTextColorMenuItem(editor, 'forecolor', 'forecolor', 'Text color', lastForeColor);
  11928. registerTextColorMenuItem(editor, 'backcolor', 'hilitecolor', 'Background color', lastBackColor);
  11929. };
  11930. const createPartialChoiceMenu = (value, items, onItemValueHandler, columns, presets, itemResponse, select, providersBackstage) => {
  11931. const hasIcons = menuHasIcons(items);
  11932. const presetItemTypes = presets !== 'color' ? 'normal' : 'color';
  11933. const alloyItems = createChoiceItems(items, onItemValueHandler, columns, presetItemTypes, itemResponse, select, providersBackstage);
  11934. const menuLayout = { menuType: presets };
  11935. return createPartialMenuWithAlloyItems(value, hasIcons, alloyItems, columns, menuLayout);
  11936. };
  11937. const createChoiceItems = (items, onItemValueHandler, columns, itemPresets, itemResponse, select, providersBackstage) => cat(map$2(items, item => {
  11938. if (item.type === 'choiceitem') {
  11939. return createChoiceMenuItem(item).fold(handleError, d => Optional.some(renderChoiceItem(d, columns === 1, itemPresets, onItemValueHandler, select(d.value), itemResponse, providersBackstage, menuHasIcons(items))));
  11940. } else {
  11941. return Optional.none();
  11942. }
  11943. }));
  11944. const deriveMenuMovement = (columns, presets) => {
  11945. const menuMarkers = markers(presets);
  11946. if (columns === 1) {
  11947. return {
  11948. mode: 'menu',
  11949. moveOnTab: true
  11950. };
  11951. } else if (columns === 'auto') {
  11952. return {
  11953. mode: 'grid',
  11954. selector: '.' + menuMarkers.item,
  11955. initSize: {
  11956. numColumns: 1,
  11957. numRows: 1
  11958. }
  11959. };
  11960. } else {
  11961. const rowClass = presets === 'color' ? 'tox-swatches__row' : 'tox-collection__group';
  11962. return {
  11963. mode: 'matrix',
  11964. rowSelector: '.' + rowClass,
  11965. previousSelector: menu => {
  11966. return presets === 'color' ? descendant(menu.element, '[aria-checked=true]') : Optional.none();
  11967. }
  11968. };
  11969. }
  11970. };
  11971. const deriveCollectionMovement = (columns, presets) => {
  11972. if (columns === 1) {
  11973. return {
  11974. mode: 'menu',
  11975. moveOnTab: false,
  11976. selector: '.tox-collection__item'
  11977. };
  11978. } else if (columns === 'auto') {
  11979. return {
  11980. mode: 'flatgrid',
  11981. selector: '.' + 'tox-collection__item',
  11982. initSize: {
  11983. numColumns: 1,
  11984. numRows: 1
  11985. }
  11986. };
  11987. } else {
  11988. return {
  11989. mode: 'matrix',
  11990. selectors: {
  11991. row: presets === 'color' ? '.tox-swatches__row' : '.tox-collection__group',
  11992. cell: presets === 'color' ? `.${ colorClass }` : `.${ selectableClass }`
  11993. }
  11994. };
  11995. }
  11996. };
  11997. const renderColorSwatchItem = (spec, backstage) => {
  11998. const items = getColorItems(spec, backstage);
  11999. const columns = backstage.colorinput.getColorCols(spec.initData.storageKey);
  12000. const presets = 'color';
  12001. const menuSpec = createPartialChoiceMenu(generate$6('menu-value'), items, value => {
  12002. spec.onAction({ value });
  12003. }, columns, presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), backstage.shared.providers);
  12004. const widgetSpec = {
  12005. ...menuSpec,
  12006. markers: markers(presets),
  12007. movement: deriveMenuMovement(columns, presets)
  12008. };
  12009. return {
  12010. type: 'widget',
  12011. data: { value: generate$6('widget-id') },
  12012. dom: {
  12013. tag: 'div',
  12014. classes: ['tox-fancymenuitem']
  12015. },
  12016. autofocus: true,
  12017. components: [parts$f.widget(Menu.sketch(widgetSpec))]
  12018. };
  12019. };
  12020. const getColorItems = (spec, backstage) => {
  12021. const useCustomColors = spec.initData.allowCustomColors && backstage.colorinput.hasCustomColors();
  12022. return spec.initData.colors.fold(() => getColors$1(backstage.colorinput.getColors(spec.initData.storageKey), spec.initData.storageKey, useCustomColors), colors => colors.concat(getAdditionalColors(useCustomColors)));
  12023. };
  12024. const cellOverEvent = generate$6('cell-over');
  12025. const cellExecuteEvent = generate$6('cell-execute');
  12026. const makeAnnouncementText = backstage => (row, col) => backstage.shared.providers.translate([
  12027. '{0} columns, {1} rows',
  12028. col,
  12029. row
  12030. ]);
  12031. const makeCell = (row, col, label) => {
  12032. const emitCellOver = c => emitWith(c, cellOverEvent, {
  12033. row,
  12034. col
  12035. });
  12036. const emitExecute = c => emitWith(c, cellExecuteEvent, {
  12037. row,
  12038. col
  12039. });
  12040. const onClick = (c, se) => {
  12041. se.stop();
  12042. emitExecute(c);
  12043. };
  12044. return build$1({
  12045. dom: {
  12046. tag: 'div',
  12047. attributes: {
  12048. role: 'button',
  12049. ['aria-label']: label
  12050. }
  12051. },
  12052. behaviours: derive$1([
  12053. config('insert-table-picker-cell', [
  12054. run$1(mouseover(), Focusing.focus),
  12055. run$1(execute$5(), emitExecute),
  12056. run$1(click(), onClick),
  12057. run$1(tap(), onClick)
  12058. ]),
  12059. Toggling.config({
  12060. toggleClass: 'tox-insert-table-picker__selected',
  12061. toggleOnExecute: false
  12062. }),
  12063. Focusing.config({ onFocus: emitCellOver })
  12064. ])
  12065. });
  12066. };
  12067. const makeCells = (getCellLabel, numRows, numCols) => {
  12068. const cells = [];
  12069. for (let i = 0; i < numRows; i++) {
  12070. const row = [];
  12071. for (let j = 0; j < numCols; j++) {
  12072. const label = getCellLabel(i + 1, j + 1);
  12073. row.push(makeCell(i, j, label));
  12074. }
  12075. cells.push(row);
  12076. }
  12077. return cells;
  12078. };
  12079. const selectCells = (cells, selectedRow, selectedColumn, numRows, numColumns) => {
  12080. for (let i = 0; i < numRows; i++) {
  12081. for (let j = 0; j < numColumns; j++) {
  12082. Toggling.set(cells[i][j], i <= selectedRow && j <= selectedColumn);
  12083. }
  12084. }
  12085. };
  12086. const makeComponents = cells => bind$3(cells, cellRow => map$2(cellRow, premade));
  12087. const makeLabelText = (row, col) => text$2(`${ col }x${ row }`);
  12088. const renderInsertTableMenuItem = (spec, backstage) => {
  12089. const numRows = 10;
  12090. const numColumns = 10;
  12091. const getCellLabel = makeAnnouncementText(backstage);
  12092. const cells = makeCells(getCellLabel, numRows, numColumns);
  12093. const emptyLabelText = makeLabelText(0, 0);
  12094. const memLabel = record({
  12095. dom: {
  12096. tag: 'span',
  12097. classes: ['tox-insert-table-picker__label']
  12098. },
  12099. components: [emptyLabelText],
  12100. behaviours: derive$1([Replacing.config({})])
  12101. });
  12102. return {
  12103. type: 'widget',
  12104. data: { value: generate$6('widget-id') },
  12105. dom: {
  12106. tag: 'div',
  12107. classes: ['tox-fancymenuitem']
  12108. },
  12109. autofocus: true,
  12110. components: [parts$f.widget({
  12111. dom: {
  12112. tag: 'div',
  12113. classes: ['tox-insert-table-picker']
  12114. },
  12115. components: makeComponents(cells).concat(memLabel.asSpec()),
  12116. behaviours: derive$1([
  12117. config('insert-table-picker', [
  12118. runOnAttached(c => {
  12119. Replacing.set(memLabel.get(c), [emptyLabelText]);
  12120. }),
  12121. runWithTarget(cellOverEvent, (c, t, e) => {
  12122. const {row, col} = e.event;
  12123. selectCells(cells, row, col, numRows, numColumns);
  12124. Replacing.set(memLabel.get(c), [makeLabelText(row + 1, col + 1)]);
  12125. }),
  12126. runWithTarget(cellExecuteEvent, (c, _, e) => {
  12127. const {row, col} = e.event;
  12128. spec.onAction({
  12129. numRows: row + 1,
  12130. numColumns: col + 1
  12131. });
  12132. emit(c, sandboxClose());
  12133. })
  12134. ]),
  12135. Keying.config({
  12136. initSize: {
  12137. numRows,
  12138. numColumns
  12139. },
  12140. mode: 'flatgrid',
  12141. selector: '[role="button"]'
  12142. })
  12143. ])
  12144. })]
  12145. };
  12146. };
  12147. const fancyMenuItems = {
  12148. inserttable: renderInsertTableMenuItem,
  12149. colorswatch: renderColorSwatchItem
  12150. };
  12151. const renderFancyMenuItem = (spec, backstage) => get$g(fancyMenuItems, spec.fancytype).map(render => render(spec, backstage));
  12152. const renderNestedItem = (spec, itemResponse, providersBackstage, renderIcons = true, downwardsCaret = false) => {
  12153. const caret = downwardsCaret ? renderDownwardsCaret(providersBackstage.icons) : renderSubmenuCaret(providersBackstage.icons);
  12154. const getApi = component => ({
  12155. isEnabled: () => !Disabling.isDisabled(component),
  12156. setEnabled: state => Disabling.set(component, !state),
  12157. setIconFill: (id, value) => {
  12158. descendant(component.element, `svg path[class="${ id }"], rect[class="${ id }"]`).each(underlinePath => {
  12159. set$9(underlinePath, 'fill', value);
  12160. });
  12161. },
  12162. setTooltip: tooltip => {
  12163. const translatedTooltip = providersBackstage.translate(tooltip);
  12164. setAll$1(component.element, {
  12165. 'aria-label': translatedTooltip,
  12166. 'title': translatedTooltip
  12167. });
  12168. }
  12169. });
  12170. const structure = renderItemStructure({
  12171. presets: 'normal',
  12172. iconContent: spec.icon,
  12173. textContent: spec.text,
  12174. htmlContent: Optional.none(),
  12175. ariaLabel: spec.text,
  12176. caret: Optional.some(caret),
  12177. checkMark: Optional.none(),
  12178. shortcutContent: spec.shortcut
  12179. }, providersBackstage, renderIcons);
  12180. return renderCommonItem({
  12181. data: buildData(spec),
  12182. getApi,
  12183. enabled: spec.enabled,
  12184. onAction: noop,
  12185. onSetup: spec.onSetup,
  12186. triggersSubmenu: true,
  12187. itemBehaviours: []
  12188. }, structure, itemResponse, providersBackstage);
  12189. };
  12190. const renderNormalItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
  12191. const getApi = component => ({
  12192. isEnabled: () => !Disabling.isDisabled(component),
  12193. setEnabled: state => Disabling.set(component, !state)
  12194. });
  12195. const structure = renderItemStructure({
  12196. presets: 'normal',
  12197. iconContent: spec.icon,
  12198. textContent: spec.text,
  12199. htmlContent: Optional.none(),
  12200. ariaLabel: spec.text,
  12201. caret: Optional.none(),
  12202. checkMark: Optional.none(),
  12203. shortcutContent: spec.shortcut
  12204. }, providersBackstage, renderIcons);
  12205. return renderCommonItem({
  12206. data: buildData(spec),
  12207. getApi,
  12208. enabled: spec.enabled,
  12209. onAction: spec.onAction,
  12210. onSetup: spec.onSetup,
  12211. triggersSubmenu: false,
  12212. itemBehaviours: []
  12213. }, structure, itemResponse, providersBackstage);
  12214. };
  12215. const renderSeparatorItem = spec => ({
  12216. type: 'separator',
  12217. dom: {
  12218. tag: 'div',
  12219. classes: [
  12220. selectableClass,
  12221. groupHeadingClass
  12222. ]
  12223. },
  12224. components: spec.text.map(text$2).toArray()
  12225. });
  12226. const renderToggleMenuItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
  12227. const getApi = component => ({
  12228. setActive: state => {
  12229. Toggling.set(component, state);
  12230. },
  12231. isActive: () => Toggling.isOn(component),
  12232. isEnabled: () => !Disabling.isDisabled(component),
  12233. setEnabled: state => Disabling.set(component, !state)
  12234. });
  12235. const structure = renderItemStructure({
  12236. iconContent: spec.icon,
  12237. textContent: spec.text,
  12238. htmlContent: Optional.none(),
  12239. ariaLabel: spec.text,
  12240. checkMark: Optional.some(renderCheckmark(providersBackstage.icons)),
  12241. caret: Optional.none(),
  12242. shortcutContent: spec.shortcut,
  12243. presets: 'normal',
  12244. meta: spec.meta
  12245. }, providersBackstage, renderIcons);
  12246. return deepMerge(renderCommonItem({
  12247. data: buildData(spec),
  12248. enabled: spec.enabled,
  12249. getApi,
  12250. onAction: spec.onAction,
  12251. onSetup: spec.onSetup,
  12252. triggersSubmenu: false,
  12253. itemBehaviours: []
  12254. }, structure, itemResponse, providersBackstage), {
  12255. toggling: {
  12256. toggleClass: tickedClass,
  12257. toggleOnExecute: false,
  12258. selected: spec.active
  12259. }
  12260. });
  12261. };
  12262. const autocomplete = renderAutocompleteItem;
  12263. const separator$3 = renderSeparatorItem;
  12264. const normal = renderNormalItem;
  12265. const nested = renderNestedItem;
  12266. const toggle$1 = renderToggleMenuItem;
  12267. const fancy = renderFancyMenuItem;
  12268. const card = renderCardMenuItem;
  12269. const getCoupled = (component, coupleConfig, coupleState, name) => coupleState.getOrCreate(component, coupleConfig, name);
  12270. const getExistingCoupled = (component, coupleConfig, coupleState, name) => coupleState.getExisting(component, coupleConfig, name);
  12271. var CouplingApis = /*#__PURE__*/Object.freeze({
  12272. __proto__: null,
  12273. getCoupled: getCoupled,
  12274. getExistingCoupled: getExistingCoupled
  12275. });
  12276. var CouplingSchema = [requiredOf('others', setOf(Result.value, anyValue()))];
  12277. const init$a = () => {
  12278. const coupled = {};
  12279. const lookupCoupled = (coupleConfig, coupledName) => {
  12280. const available = keys(coupleConfig.others);
  12281. if (available.length === 0) {
  12282. throw new Error('Cannot find any known coupled components');
  12283. } else {
  12284. return get$g(coupled, coupledName);
  12285. }
  12286. };
  12287. const getOrCreate = (component, coupleConfig, name) => {
  12288. return lookupCoupled(coupleConfig, name).getOrThunk(() => {
  12289. const builder = get$g(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
  12290. const spec = builder(component);
  12291. const built = component.getSystem().build(spec);
  12292. coupled[name] = built;
  12293. return built;
  12294. });
  12295. };
  12296. const getExisting = (component, coupleConfig, name) => {
  12297. return lookupCoupled(coupleConfig, name).orThunk(() => {
  12298. get$g(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
  12299. return Optional.none();
  12300. });
  12301. };
  12302. const readState = constant$1({});
  12303. return nu$8({
  12304. readState,
  12305. getExisting,
  12306. getOrCreate
  12307. });
  12308. };
  12309. var CouplingState = /*#__PURE__*/Object.freeze({
  12310. __proto__: null,
  12311. init: init$a
  12312. });
  12313. const Coupling = create$4({
  12314. fields: CouplingSchema,
  12315. name: 'coupling',
  12316. apis: CouplingApis,
  12317. state: CouplingState
  12318. });
  12319. const nu$3 = baseFn => {
  12320. let data = Optional.none();
  12321. let callbacks = [];
  12322. const map = f => nu$3(nCallback => {
  12323. get(data => {
  12324. nCallback(f(data));
  12325. });
  12326. });
  12327. const get = nCallback => {
  12328. if (isReady()) {
  12329. call(nCallback);
  12330. } else {
  12331. callbacks.push(nCallback);
  12332. }
  12333. };
  12334. const set = x => {
  12335. if (!isReady()) {
  12336. data = Optional.some(x);
  12337. run(callbacks);
  12338. callbacks = [];
  12339. }
  12340. };
  12341. const isReady = () => data.isSome();
  12342. const run = cbs => {
  12343. each$1(cbs, call);
  12344. };
  12345. const call = cb => {
  12346. data.each(x => {
  12347. setTimeout(() => {
  12348. cb(x);
  12349. }, 0);
  12350. });
  12351. };
  12352. baseFn(set);
  12353. return {
  12354. get,
  12355. map,
  12356. isReady
  12357. };
  12358. };
  12359. const pure$1 = a => nu$3(callback => {
  12360. callback(a);
  12361. });
  12362. const LazyValue = {
  12363. nu: nu$3,
  12364. pure: pure$1
  12365. };
  12366. const errorReporter = err => {
  12367. setTimeout(() => {
  12368. throw err;
  12369. }, 0);
  12370. };
  12371. const make$5 = run => {
  12372. const get = callback => {
  12373. run().then(callback, errorReporter);
  12374. };
  12375. const map = fab => {
  12376. return make$5(() => run().then(fab));
  12377. };
  12378. const bind = aFutureB => {
  12379. return make$5(() => run().then(v => aFutureB(v).toPromise()));
  12380. };
  12381. const anonBind = futureB => {
  12382. return make$5(() => run().then(() => futureB.toPromise()));
  12383. };
  12384. const toLazy = () => {
  12385. return LazyValue.nu(get);
  12386. };
  12387. const toCached = () => {
  12388. let cache = null;
  12389. return make$5(() => {
  12390. if (cache === null) {
  12391. cache = run();
  12392. }
  12393. return cache;
  12394. });
  12395. };
  12396. const toPromise = run;
  12397. return {
  12398. map,
  12399. bind,
  12400. anonBind,
  12401. toLazy,
  12402. toCached,
  12403. toPromise,
  12404. get
  12405. };
  12406. };
  12407. const nu$2 = baseFn => {
  12408. return make$5(() => new Promise(baseFn));
  12409. };
  12410. const pure = a => {
  12411. return make$5(() => Promise.resolve(a));
  12412. };
  12413. const Future = {
  12414. nu: nu$2,
  12415. pure
  12416. };
  12417. const suffix = constant$1('sink');
  12418. const partType$1 = constant$1(optional({
  12419. name: suffix(),
  12420. overrides: constant$1({
  12421. dom: { tag: 'div' },
  12422. behaviours: derive$1([Positioning.config({ useFixed: always })]),
  12423. events: derive$2([
  12424. cutter(keydown()),
  12425. cutter(mousedown()),
  12426. cutter(click())
  12427. ])
  12428. })
  12429. }));
  12430. const getAnchor = (detail, component) => {
  12431. const hotspot = detail.getHotspot(component).getOr(component);
  12432. const type = 'hotspot';
  12433. const overrides = detail.getAnchorOverrides();
  12434. return detail.layouts.fold(() => ({
  12435. type,
  12436. hotspot,
  12437. overrides
  12438. }), layouts => ({
  12439. type,
  12440. hotspot,
  12441. overrides,
  12442. layouts
  12443. }));
  12444. };
  12445. const fetch = (detail, mapFetch, component) => {
  12446. const fetcher = detail.fetch;
  12447. return fetcher(component).map(mapFetch);
  12448. };
  12449. const openF = (detail, mapFetch, anchor, component, sandbox, externals, highlightOnOpen) => {
  12450. const futureData = fetch(detail, mapFetch, component);
  12451. const getLazySink = getSink(component, detail);
  12452. return futureData.map(tdata => tdata.bind(data => Optional.from(tieredMenu.sketch({
  12453. ...externals.menu(),
  12454. uid: generate$5(''),
  12455. data,
  12456. highlightOnOpen,
  12457. onOpenMenu: (tmenu, menu) => {
  12458. const sink = getLazySink().getOrDie();
  12459. Positioning.position(sink, menu, { anchor });
  12460. Sandboxing.decloak(sandbox);
  12461. },
  12462. onOpenSubmenu: (tmenu, item, submenu) => {
  12463. const sink = getLazySink().getOrDie();
  12464. Positioning.position(sink, submenu, {
  12465. anchor: {
  12466. type: 'submenu',
  12467. item
  12468. }
  12469. });
  12470. Sandboxing.decloak(sandbox);
  12471. },
  12472. onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
  12473. const sink = getLazySink().getOrDie();
  12474. Positioning.position(sink, primaryMenu, { anchor });
  12475. each$1(submenuTriggers, st => {
  12476. Positioning.position(sink, st.triggeredMenu, {
  12477. anchor: {
  12478. type: 'submenu',
  12479. item: st.triggeringItem
  12480. }
  12481. });
  12482. });
  12483. },
  12484. onEscape: () => {
  12485. Focusing.focus(component);
  12486. Sandboxing.close(sandbox);
  12487. return Optional.some(true);
  12488. }
  12489. }))));
  12490. };
  12491. const open = (detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen) => {
  12492. const anchor = getAnchor(detail, hotspot);
  12493. const processed = openF(detail, mapFetch, anchor, hotspot, sandbox, externals, highlightOnOpen);
  12494. return processed.map(tdata => {
  12495. tdata.fold(() => {
  12496. if (Sandboxing.isOpen(sandbox)) {
  12497. Sandboxing.close(sandbox);
  12498. }
  12499. }, data => {
  12500. Sandboxing.cloak(sandbox);
  12501. Sandboxing.open(sandbox, data);
  12502. onOpenSync(sandbox);
  12503. });
  12504. return sandbox;
  12505. });
  12506. };
  12507. const close = (detail, mapFetch, component, sandbox, _externals, _onOpenSync, _highlightOnOpen) => {
  12508. Sandboxing.close(sandbox);
  12509. return Future.pure(sandbox);
  12510. };
  12511. const togglePopup = (detail, mapFetch, hotspot, externals, onOpenSync, highlightOnOpen) => {
  12512. const sandbox = Coupling.getCoupled(hotspot, 'sandbox');
  12513. const showing = Sandboxing.isOpen(sandbox);
  12514. const action = showing ? close : open;
  12515. return action(detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen);
  12516. };
  12517. const matchWidth = (hotspot, container, useMinWidth) => {
  12518. const menu = Composing.getCurrent(container).getOr(container);
  12519. const buttonWidth = get$c(hotspot.element);
  12520. if (useMinWidth) {
  12521. set$8(menu.element, 'min-width', buttonWidth + 'px');
  12522. } else {
  12523. set$7(menu.element, buttonWidth);
  12524. }
  12525. };
  12526. const getSink = (anyInSystem, sinkDetail) => anyInSystem.getSystem().getByUid(sinkDetail.uid + '-' + suffix()).map(internalSink => () => Result.value(internalSink)).getOrThunk(() => sinkDetail.lazySink.fold(() => () => Result.error(new Error('No internal sink is specified, nor could an external sink be found')), lazySinkFn => () => lazySinkFn(anyInSystem)));
  12527. const doRepositionMenus = sandbox => {
  12528. Sandboxing.getState(sandbox).each(tmenu => {
  12529. tieredMenu.repositionMenus(tmenu);
  12530. });
  12531. };
  12532. const makeSandbox$1 = (detail, hotspot, extras) => {
  12533. const ariaControls = manager();
  12534. const onOpen = (component, menu) => {
  12535. const anchor = getAnchor(detail, hotspot);
  12536. ariaControls.link(hotspot.element);
  12537. if (detail.matchWidth) {
  12538. matchWidth(anchor.hotspot, menu, detail.useMinWidth);
  12539. }
  12540. detail.onOpen(anchor, component, menu);
  12541. if (extras !== undefined && extras.onOpen !== undefined) {
  12542. extras.onOpen(component, menu);
  12543. }
  12544. };
  12545. const onClose = (component, menu) => {
  12546. ariaControls.unlink(hotspot.element);
  12547. if (extras !== undefined && extras.onClose !== undefined) {
  12548. extras.onClose(component, menu);
  12549. }
  12550. };
  12551. const lazySink = getSink(hotspot, detail);
  12552. return {
  12553. dom: {
  12554. tag: 'div',
  12555. classes: detail.sandboxClasses,
  12556. attributes: {
  12557. id: ariaControls.id,
  12558. role: 'listbox'
  12559. }
  12560. },
  12561. behaviours: SketchBehaviours.augment(detail.sandboxBehaviours, [
  12562. Representing.config({
  12563. store: {
  12564. mode: 'memory',
  12565. initialValue: hotspot
  12566. }
  12567. }),
  12568. Sandboxing.config({
  12569. onOpen,
  12570. onClose,
  12571. isPartOf: (container, data, queryElem) => {
  12572. return isPartOf$1(data, queryElem) || isPartOf$1(hotspot, queryElem);
  12573. },
  12574. getAttachPoint: () => {
  12575. return lazySink().getOrDie();
  12576. }
  12577. }),
  12578. Composing.config({
  12579. find: sandbox => {
  12580. return Sandboxing.getState(sandbox).bind(menu => Composing.getCurrent(menu));
  12581. }
  12582. }),
  12583. Receiving.config({
  12584. channels: {
  12585. ...receivingChannel$1({ isExtraPart: never }),
  12586. ...receivingChannel({ doReposition: doRepositionMenus })
  12587. }
  12588. })
  12589. ])
  12590. };
  12591. };
  12592. const repositionMenus = comp => {
  12593. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  12594. doRepositionMenus(sandbox);
  12595. };
  12596. const sandboxFields = () => [
  12597. defaulted('sandboxClasses', []),
  12598. SketchBehaviours.field('sandboxBehaviours', [
  12599. Composing,
  12600. Receiving,
  12601. Sandboxing,
  12602. Representing
  12603. ])
  12604. ];
  12605. const schema$k = constant$1([
  12606. required$1('dom'),
  12607. required$1('fetch'),
  12608. onHandler('onOpen'),
  12609. onKeyboardHandler('onExecute'),
  12610. defaulted('getHotspot', Optional.some),
  12611. defaulted('getAnchorOverrides', constant$1({})),
  12612. schema$y(),
  12613. field('dropdownBehaviours', [
  12614. Toggling,
  12615. Coupling,
  12616. Keying,
  12617. Focusing
  12618. ]),
  12619. required$1('toggleClass'),
  12620. defaulted('eventOrder', {}),
  12621. option$3('lazySink'),
  12622. defaulted('matchWidth', false),
  12623. defaulted('useMinWidth', false),
  12624. option$3('role')
  12625. ].concat(sandboxFields()));
  12626. const parts$e = constant$1([
  12627. external({
  12628. schema: [
  12629. tieredMenuMarkers(),
  12630. defaulted('fakeFocus', false)
  12631. ],
  12632. name: 'menu',
  12633. defaults: detail => {
  12634. return { onExecute: detail.onExecute };
  12635. }
  12636. }),
  12637. partType$1()
  12638. ]);
  12639. const factory$k = (detail, components, _spec, externals) => {
  12640. const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
  12641. const switchToMenu = sandbox => {
  12642. Sandboxing.getState(sandbox).each(tmenu => {
  12643. tieredMenu.highlightPrimary(tmenu);
  12644. });
  12645. };
  12646. const togglePopup$1 = (dropdownComp, onOpenSync, highlightOnOpen) => {
  12647. return togglePopup(detail, identity, dropdownComp, externals, onOpenSync, highlightOnOpen);
  12648. };
  12649. const action = component => {
  12650. const onOpenSync = switchToMenu;
  12651. togglePopup$1(component, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  12652. };
  12653. const apis = {
  12654. expand: comp => {
  12655. if (!Toggling.isOn(comp)) {
  12656. togglePopup$1(comp, noop, HighlightOnOpen.HighlightNone).get(noop);
  12657. }
  12658. },
  12659. open: comp => {
  12660. if (!Toggling.isOn(comp)) {
  12661. togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  12662. }
  12663. },
  12664. refetch: comp => {
  12665. const optSandbox = Coupling.getExistingCoupled(comp, 'sandbox');
  12666. return optSandbox.fold(() => {
  12667. return togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
  12668. }, sandboxComp => {
  12669. return open(detail, identity, comp, sandboxComp, externals, noop, HighlightOnOpen.HighlightMenuAndItem).map(noop);
  12670. });
  12671. },
  12672. isOpen: Toggling.isOn,
  12673. close: comp => {
  12674. if (Toggling.isOn(comp)) {
  12675. togglePopup$1(comp, noop, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  12676. }
  12677. },
  12678. repositionMenus: comp => {
  12679. if (Toggling.isOn(comp)) {
  12680. repositionMenus(comp);
  12681. }
  12682. }
  12683. };
  12684. const triggerExecute = (comp, _se) => {
  12685. emitExecute(comp);
  12686. return Optional.some(true);
  12687. };
  12688. return {
  12689. uid: detail.uid,
  12690. dom: detail.dom,
  12691. components,
  12692. behaviours: augment(detail.dropdownBehaviours, [
  12693. Toggling.config({
  12694. toggleClass: detail.toggleClass,
  12695. aria: { mode: 'expanded' }
  12696. }),
  12697. Coupling.config({
  12698. others: {
  12699. sandbox: hotspot => {
  12700. return makeSandbox$1(detail, hotspot, {
  12701. onOpen: () => Toggling.on(hotspot),
  12702. onClose: () => Toggling.off(hotspot)
  12703. });
  12704. }
  12705. }
  12706. }),
  12707. Keying.config({
  12708. mode: 'special',
  12709. onSpace: triggerExecute,
  12710. onEnter: triggerExecute,
  12711. onDown: (comp, _se) => {
  12712. if (Dropdown.isOpen(comp)) {
  12713. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  12714. switchToMenu(sandbox);
  12715. } else {
  12716. Dropdown.open(comp);
  12717. }
  12718. return Optional.some(true);
  12719. },
  12720. onEscape: (comp, _se) => {
  12721. if (Dropdown.isOpen(comp)) {
  12722. Dropdown.close(comp);
  12723. return Optional.some(true);
  12724. } else {
  12725. return Optional.none();
  12726. }
  12727. }
  12728. }),
  12729. Focusing.config({})
  12730. ]),
  12731. events: events$a(Optional.some(action)),
  12732. eventOrder: {
  12733. ...detail.eventOrder,
  12734. [execute$5()]: [
  12735. 'disabling',
  12736. 'toggling',
  12737. 'alloy.base.behaviour'
  12738. ]
  12739. },
  12740. apis,
  12741. domModification: {
  12742. attributes: {
  12743. 'aria-haspopup': 'true',
  12744. ...detail.role.fold(() => ({}), role => ({ role })),
  12745. ...detail.dom.tag === 'button' ? { type: lookupAttr('type').getOr('button') } : {}
  12746. }
  12747. }
  12748. };
  12749. };
  12750. const Dropdown = composite({
  12751. name: 'Dropdown',
  12752. configFields: schema$k(),
  12753. partFields: parts$e(),
  12754. factory: factory$k,
  12755. apis: {
  12756. open: (apis, comp) => apis.open(comp),
  12757. refetch: (apis, comp) => apis.refetch(comp),
  12758. expand: (apis, comp) => apis.expand(comp),
  12759. close: (apis, comp) => apis.close(comp),
  12760. isOpen: (apis, comp) => apis.isOpen(comp),
  12761. repositionMenus: (apis, comp) => apis.repositionMenus(comp)
  12762. }
  12763. });
  12764. const identifyMenuLayout = searchMode => {
  12765. switch (searchMode.searchMode) {
  12766. case 'no-search': {
  12767. return { menuType: 'normal' };
  12768. }
  12769. default: {
  12770. return {
  12771. menuType: 'searchable',
  12772. searchMode
  12773. };
  12774. }
  12775. }
  12776. };
  12777. const handleRefetchTrigger = originalSandboxComp => {
  12778. const dropdown = Representing.getValue(originalSandboxComp);
  12779. const optSearcherState = findWithinSandbox(originalSandboxComp).map(saveState);
  12780. Dropdown.refetch(dropdown).get(() => {
  12781. const newSandboxComp = Coupling.getCoupled(dropdown, 'sandbox');
  12782. optSearcherState.each(searcherState => findWithinSandbox(newSandboxComp).each(inputComp => restoreState(inputComp, searcherState)));
  12783. });
  12784. };
  12785. const handleRedirectToMenuItem = (sandboxComp, se) => {
  12786. getActiveMenuItemFrom(sandboxComp).each(activeItem => {
  12787. retargetAndDispatchWith(sandboxComp, activeItem.element, se.event.eventType, se.event.interactionEvent);
  12788. });
  12789. };
  12790. const getActiveMenuItemFrom = sandboxComp => {
  12791. return Sandboxing.getState(sandboxComp).bind(Highlighting.getHighlighted).bind(Highlighting.getHighlighted);
  12792. };
  12793. const getSearchResults = activeMenuComp => {
  12794. return has(activeMenuComp.element, searchResultsClass) ? Optional.some(activeMenuComp.element) : descendant(activeMenuComp.element, '.' + searchResultsClass);
  12795. };
  12796. const updateAriaOnHighlight = (tmenuComp, menuComp, itemComp) => {
  12797. findWithinMenu(tmenuComp).each(inputComp => {
  12798. setActiveDescendant(inputComp, itemComp);
  12799. const optActiveResults = getSearchResults(menuComp);
  12800. optActiveResults.each(resultsElem => {
  12801. getOpt(resultsElem, 'id').each(controlledId => set$9(inputComp.element, 'aria-controls', controlledId));
  12802. });
  12803. });
  12804. set$9(itemComp.element, 'aria-selected', 'true');
  12805. };
  12806. const updateAriaOnDehighlight = (tmenuComp, menuComp, itemComp) => {
  12807. set$9(itemComp.element, 'aria-selected', 'false');
  12808. };
  12809. const focusSearchField = tmenuComp => {
  12810. findWithinMenu(tmenuComp).each(searcherComp => Focusing.focus(searcherComp));
  12811. };
  12812. const getSearchPattern = dropdownComp => {
  12813. const optSandboxComp = Coupling.getExistingCoupled(dropdownComp, 'sandbox');
  12814. return optSandboxComp.bind(findWithinSandbox).map(saveState).map(state => state.fetchPattern).getOr('');
  12815. };
  12816. var FocusMode;
  12817. (function (FocusMode) {
  12818. FocusMode[FocusMode['ContentFocus'] = 0] = 'ContentFocus';
  12819. FocusMode[FocusMode['UiFocus'] = 1] = 'UiFocus';
  12820. }(FocusMode || (FocusMode = {})));
  12821. const createMenuItemFromBridge = (item, itemResponse, backstage, menuHasIcons, isHorizontalMenu) => {
  12822. const providersBackstage = backstage.shared.providers;
  12823. const parseForHorizontalMenu = menuitem => !isHorizontalMenu ? menuitem : {
  12824. ...menuitem,
  12825. shortcut: Optional.none(),
  12826. icon: menuitem.text.isSome() ? Optional.none() : menuitem.icon
  12827. };
  12828. switch (item.type) {
  12829. case 'menuitem':
  12830. return createMenuItem(item).fold(handleError, d => Optional.some(normal(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
  12831. case 'nestedmenuitem':
  12832. return createNestedMenuItem(item).fold(handleError, d => Optional.some(nested(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons, isHorizontalMenu)));
  12833. case 'togglemenuitem':
  12834. return createToggleMenuItem(item).fold(handleError, d => Optional.some(toggle$1(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
  12835. case 'separator':
  12836. return createSeparatorMenuItem(item).fold(handleError, d => Optional.some(separator$3(d)));
  12837. case 'fancymenuitem':
  12838. return createFancyMenuItem(item).fold(handleError, d => fancy(d, backstage));
  12839. default: {
  12840. console.error('Unknown item in general menu', item);
  12841. return Optional.none();
  12842. }
  12843. }
  12844. };
  12845. const createAutocompleteItems = (items, matchText, onItemValueHandler, columns, itemResponse, sharedBackstage, highlightOn) => {
  12846. const renderText = columns === 1;
  12847. const renderIcons = !renderText || menuHasIcons(items);
  12848. return cat(map$2(items, item => {
  12849. switch (item.type) {
  12850. case 'separator':
  12851. return createSeparatorItem(item).fold(handleError, d => Optional.some(separator$3(d)));
  12852. case 'cardmenuitem':
  12853. return createCardMenuItem(item).fold(handleError, d => Optional.some(card({
  12854. ...d,
  12855. onAction: api => {
  12856. d.onAction(api);
  12857. onItemValueHandler(d.value, d.meta);
  12858. }
  12859. }, itemResponse, sharedBackstage, {
  12860. itemBehaviours: tooltipBehaviour(d.meta, sharedBackstage),
  12861. cardText: {
  12862. matchText,
  12863. highlightOn
  12864. }
  12865. })));
  12866. case 'autocompleteitem':
  12867. default:
  12868. return createAutocompleterItem(item).fold(handleError, d => Optional.some(autocomplete(d, matchText, renderText, 'normal', onItemValueHandler, itemResponse, sharedBackstage, renderIcons)));
  12869. }
  12870. }));
  12871. };
  12872. const createPartialMenu = (value, items, itemResponse, backstage, isHorizontalMenu, searchMode) => {
  12873. const hasIcons = menuHasIcons(items);
  12874. const alloyItems = cat(map$2(items, item => {
  12875. const itemHasIcon = i => isHorizontalMenu ? !has$2(i, 'text') : hasIcons;
  12876. const createItem = i => createMenuItemFromBridge(i, itemResponse, backstage, itemHasIcon(i), isHorizontalMenu);
  12877. if (item.type === 'nestedmenuitem' && item.getSubmenuItems().length <= 0) {
  12878. return createItem({
  12879. ...item,
  12880. enabled: false
  12881. });
  12882. } else {
  12883. return createItem(item);
  12884. }
  12885. }));
  12886. const menuLayout = identifyMenuLayout(searchMode);
  12887. const createPartial = isHorizontalMenu ? createHorizontalPartialMenuWithAlloyItems : createPartialMenuWithAlloyItems;
  12888. return createPartial(value, hasIcons, alloyItems, 1, menuLayout);
  12889. };
  12890. const createTieredDataFrom = partialMenu => tieredMenu.singleData(partialMenu.value, partialMenu);
  12891. const createInlineMenuFrom = (partialMenu, columns, focusMode, presets) => {
  12892. const movement = deriveMenuMovement(columns, presets);
  12893. const menuMarkers = markers(presets);
  12894. return {
  12895. data: createTieredDataFrom({
  12896. ...partialMenu,
  12897. movement,
  12898. menuBehaviours: SimpleBehaviours.unnamedEvents(columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
  12899. detectSize(comp, 4, menuMarkers.item).each(({numColumns, numRows}) => {
  12900. Keying.setGridSize(comp, numRows, numColumns);
  12901. });
  12902. })])
  12903. }),
  12904. menu: {
  12905. markers: markers(presets),
  12906. fakeFocus: focusMode === FocusMode.ContentFocus
  12907. }
  12908. };
  12909. };
  12910. const getAutocompleterRange = (dom, initRange) => {
  12911. return detect$1(SugarElement.fromDom(initRange.startContainer)).map(elm => {
  12912. const range = dom.createRng();
  12913. range.selectNode(elm.dom);
  12914. return range;
  12915. });
  12916. };
  12917. const register$b = (editor, sharedBackstage) => {
  12918. const autocompleterId = generate$6('autocompleter');
  12919. const processingAction = Cell(false);
  12920. const activeState = Cell(false);
  12921. const autocompleter = build$1(InlineView.sketch({
  12922. dom: {
  12923. tag: 'div',
  12924. classes: ['tox-autocompleter'],
  12925. attributes: { id: autocompleterId }
  12926. },
  12927. components: [],
  12928. fireDismissalEventInstead: {},
  12929. inlineBehaviours: derive$1([config('dismissAutocompleter', [
  12930. run$1(dismissRequested(), () => cancelIfNecessary()),
  12931. run$1(highlight$1(), (_, se) => {
  12932. getOpt(se.event.target, 'id').each(id => set$9(SugarElement.fromDom(editor.getBody()), 'aria-activedescendant', id));
  12933. })
  12934. ])]),
  12935. lazySink: sharedBackstage.getSink
  12936. }));
  12937. const isMenuOpen = () => InlineView.isOpen(autocompleter);
  12938. const isActive = activeState.get;
  12939. const hideIfNecessary = () => {
  12940. if (isMenuOpen()) {
  12941. InlineView.hide(autocompleter);
  12942. editor.dom.remove(autocompleterId, false);
  12943. const editorBody = SugarElement.fromDom(editor.getBody());
  12944. getOpt(editorBody, 'aria-owns').filter(ariaOwnsAttr => ariaOwnsAttr === autocompleterId).each(() => {
  12945. remove$7(editorBody, 'aria-owns');
  12946. remove$7(editorBody, 'aria-activedescendant');
  12947. });
  12948. }
  12949. };
  12950. const getMenu = () => InlineView.getContent(autocompleter).bind(tmenu => {
  12951. return get$h(tmenu.components(), 0);
  12952. });
  12953. const cancelIfNecessary = () => editor.execCommand('mceAutocompleterClose');
  12954. const getCombinedItems = matches => {
  12955. const columns = findMap(matches, m => Optional.from(m.columns)).getOr(1);
  12956. return bind$3(matches, match => {
  12957. const choices = match.items;
  12958. return createAutocompleteItems(choices, match.matchText, (itemValue, itemMeta) => {
  12959. const nr = editor.selection.getRng();
  12960. getAutocompleterRange(editor.dom, nr).each(range => {
  12961. const autocompleterApi = {
  12962. hide: () => cancelIfNecessary(),
  12963. reload: fetchOptions => {
  12964. hideIfNecessary();
  12965. editor.execCommand('mceAutocompleterReload', false, { fetchOptions });
  12966. }
  12967. };
  12968. processingAction.set(true);
  12969. match.onAction(autocompleterApi, range, itemValue, itemMeta);
  12970. processingAction.set(false);
  12971. });
  12972. }, columns, ItemResponse$1.BUBBLE_TO_SANDBOX, sharedBackstage, match.highlightOn);
  12973. });
  12974. };
  12975. const display = (lookupData, items) => {
  12976. findIn(SugarElement.fromDom(editor.getBody())).each(element => {
  12977. const columns = findMap(lookupData, ld => Optional.from(ld.columns)).getOr(1);
  12978. InlineView.showMenuAt(autocompleter, {
  12979. anchor: {
  12980. type: 'node',
  12981. root: SugarElement.fromDom(editor.getBody()),
  12982. node: Optional.from(element)
  12983. }
  12984. }, createInlineMenuFrom(createPartialMenuWithAlloyItems('autocompleter-value', true, items, columns, { menuType: 'normal' }), columns, FocusMode.ContentFocus, 'normal'));
  12985. });
  12986. getMenu().each(Highlighting.highlightFirst);
  12987. };
  12988. const updateDisplay = lookupData => {
  12989. const combinedItems = getCombinedItems(lookupData);
  12990. if (combinedItems.length > 0) {
  12991. display(lookupData, combinedItems);
  12992. set$9(SugarElement.fromDom(editor.getBody()), 'aria-owns', autocompleterId);
  12993. if (!editor.inline) {
  12994. cloneAutocompleterToEditorDoc();
  12995. }
  12996. } else {
  12997. hideIfNecessary();
  12998. }
  12999. };
  13000. const cloneAutocompleterToEditorDoc = () => {
  13001. if (editor.dom.get(autocompleterId)) {
  13002. editor.dom.remove(autocompleterId, false);
  13003. }
  13004. const docElm = editor.getDoc().documentElement;
  13005. const selection = editor.selection.getNode();
  13006. const newElm = deep(autocompleter.element);
  13007. setAll(newElm, {
  13008. border: '0',
  13009. clip: 'rect(0 0 0 0)',
  13010. height: '1px',
  13011. margin: '-1px',
  13012. overflow: 'hidden',
  13013. padding: '0',
  13014. position: 'absolute',
  13015. width: '1px',
  13016. top: `${ selection.offsetTop }px`,
  13017. left: `${ selection.offsetLeft }px`
  13018. });
  13019. editor.dom.add(docElm, newElm.dom);
  13020. descendant(newElm, '[role="menu"]').each(child => {
  13021. remove$6(child, 'position');
  13022. remove$6(child, 'max-height');
  13023. });
  13024. };
  13025. editor.on('AutocompleterStart', ({lookupData}) => {
  13026. activeState.set(true);
  13027. processingAction.set(false);
  13028. updateDisplay(lookupData);
  13029. });
  13030. editor.on('AutocompleterUpdate', ({lookupData}) => updateDisplay(lookupData));
  13031. editor.on('AutocompleterEnd', () => {
  13032. hideIfNecessary();
  13033. activeState.set(false);
  13034. processingAction.set(false);
  13035. });
  13036. const autocompleterUiApi = {
  13037. cancelIfNecessary,
  13038. isMenuOpen,
  13039. isActive,
  13040. isProcessingAction: processingAction.get,
  13041. getMenu
  13042. };
  13043. AutocompleterEditorEvents.setup(autocompleterUiApi, editor);
  13044. };
  13045. const Autocompleter = { register: register$b };
  13046. const nonScrollingOverflows = [
  13047. 'visible',
  13048. 'hidden',
  13049. 'clip'
  13050. ];
  13051. const isScrollingOverflowValue = value => trim$1(value).length > 0 && !contains$2(nonScrollingOverflows, value);
  13052. const isScroller = elem => {
  13053. if (isHTMLElement(elem)) {
  13054. const overflowX = get$e(elem, 'overflow-x');
  13055. const overflowY = get$e(elem, 'overflow-y');
  13056. return isScrollingOverflowValue(overflowX) || isScrollingOverflowValue(overflowY);
  13057. } else {
  13058. return false;
  13059. }
  13060. };
  13061. const detect = popupSinkElem => {
  13062. const ancestorsScrollers = ancestors(popupSinkElem, isScroller);
  13063. const scrollers = ancestorsScrollers.length === 0 ? getShadowRoot(popupSinkElem).map(getShadowHost).map(x => ancestors(x, isScroller)).getOr([]) : ancestorsScrollers;
  13064. return head(scrollers).map(element => ({
  13065. element,
  13066. others: scrollers.slice(1)
  13067. }));
  13068. };
  13069. const detectWhenSplitUiMode = (editor, popupSinkElem) => isSplitUiMode(editor) ? detect(popupSinkElem) : Optional.none();
  13070. const getBoundsFrom = sc => {
  13071. const scrollableBoxes = [
  13072. ...map$2(sc.others, box$1),
  13073. win()
  13074. ];
  13075. return constrainByMany(box$1(sc.element), scrollableBoxes);
  13076. };
  13077. const closest = (scope, selector, isRoot) => closest$1(scope, selector, isRoot).isSome();
  13078. const DelayedFunction = (fun, delay) => {
  13079. let ref = null;
  13080. const schedule = (...args) => {
  13081. ref = setTimeout(() => {
  13082. fun.apply(null, args);
  13083. ref = null;
  13084. }, delay);
  13085. };
  13086. const cancel = () => {
  13087. if (ref !== null) {
  13088. clearTimeout(ref);
  13089. ref = null;
  13090. }
  13091. };
  13092. return {
  13093. cancel,
  13094. schedule
  13095. };
  13096. };
  13097. const SIGNIFICANT_MOVE = 5;
  13098. const LONGPRESS_DELAY = 400;
  13099. const getTouch = event => {
  13100. const raw = event.raw;
  13101. if (raw.touches === undefined || raw.touches.length !== 1) {
  13102. return Optional.none();
  13103. }
  13104. return Optional.some(raw.touches[0]);
  13105. };
  13106. const isFarEnough = (touch, data) => {
  13107. const distX = Math.abs(touch.clientX - data.x);
  13108. const distY = Math.abs(touch.clientY - data.y);
  13109. return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
  13110. };
  13111. const monitor = settings => {
  13112. const startData = value$2();
  13113. const longpressFired = Cell(false);
  13114. const longpress$1 = DelayedFunction(event => {
  13115. settings.triggerEvent(longpress(), event);
  13116. longpressFired.set(true);
  13117. }, LONGPRESS_DELAY);
  13118. const handleTouchstart = event => {
  13119. getTouch(event).each(touch => {
  13120. longpress$1.cancel();
  13121. const data = {
  13122. x: touch.clientX,
  13123. y: touch.clientY,
  13124. target: event.target
  13125. };
  13126. longpress$1.schedule(event);
  13127. longpressFired.set(false);
  13128. startData.set(data);
  13129. });
  13130. return Optional.none();
  13131. };
  13132. const handleTouchmove = event => {
  13133. longpress$1.cancel();
  13134. getTouch(event).each(touch => {
  13135. startData.on(data => {
  13136. if (isFarEnough(touch, data)) {
  13137. startData.clear();
  13138. }
  13139. });
  13140. });
  13141. return Optional.none();
  13142. };
  13143. const handleTouchend = event => {
  13144. longpress$1.cancel();
  13145. const isSame = data => eq(data.target, event.target);
  13146. return startData.get().filter(isSame).map(_data => {
  13147. if (longpressFired.get()) {
  13148. event.prevent();
  13149. return false;
  13150. } else {
  13151. return settings.triggerEvent(tap(), event);
  13152. }
  13153. });
  13154. };
  13155. const handlers = wrapAll([
  13156. {
  13157. key: touchstart(),
  13158. value: handleTouchstart
  13159. },
  13160. {
  13161. key: touchmove(),
  13162. value: handleTouchmove
  13163. },
  13164. {
  13165. key: touchend(),
  13166. value: handleTouchend
  13167. }
  13168. ]);
  13169. const fireIfReady = (event, type) => get$g(handlers, type).bind(handler => handler(event));
  13170. return { fireIfReady };
  13171. };
  13172. const isDangerous = event => {
  13173. const keyEv = event.raw;
  13174. return keyEv.which === BACKSPACE[0] && !contains$2([
  13175. 'input',
  13176. 'textarea'
  13177. ], name$3(event.target)) && !closest(event.target, '[contenteditable="true"]');
  13178. };
  13179. const setup$d = (container, rawSettings) => {
  13180. const settings = {
  13181. stopBackspace: true,
  13182. ...rawSettings
  13183. };
  13184. const pointerEvents = [
  13185. 'touchstart',
  13186. 'touchmove',
  13187. 'touchend',
  13188. 'touchcancel',
  13189. 'gesturestart',
  13190. 'mousedown',
  13191. 'mouseup',
  13192. 'mouseover',
  13193. 'mousemove',
  13194. 'mouseout',
  13195. 'click'
  13196. ];
  13197. const tapEvent = monitor(settings);
  13198. const simpleEvents = map$2(pointerEvents.concat([
  13199. 'selectstart',
  13200. 'input',
  13201. 'contextmenu',
  13202. 'change',
  13203. 'transitionend',
  13204. 'transitioncancel',
  13205. 'drag',
  13206. 'dragstart',
  13207. 'dragend',
  13208. 'dragenter',
  13209. 'dragleave',
  13210. 'dragover',
  13211. 'drop',
  13212. 'keyup'
  13213. ]), type => bind(container, type, event => {
  13214. tapEvent.fireIfReady(event, type).each(tapStopped => {
  13215. if (tapStopped) {
  13216. event.kill();
  13217. }
  13218. });
  13219. const stopped = settings.triggerEvent(type, event);
  13220. if (stopped) {
  13221. event.kill();
  13222. }
  13223. }));
  13224. const pasteTimeout = value$2();
  13225. const onPaste = bind(container, 'paste', event => {
  13226. tapEvent.fireIfReady(event, 'paste').each(tapStopped => {
  13227. if (tapStopped) {
  13228. event.kill();
  13229. }
  13230. });
  13231. const stopped = settings.triggerEvent('paste', event);
  13232. if (stopped) {
  13233. event.kill();
  13234. }
  13235. pasteTimeout.set(setTimeout(() => {
  13236. settings.triggerEvent(postPaste(), event);
  13237. }, 0));
  13238. });
  13239. const onKeydown = bind(container, 'keydown', event => {
  13240. const stopped = settings.triggerEvent('keydown', event);
  13241. if (stopped) {
  13242. event.kill();
  13243. } else if (settings.stopBackspace && isDangerous(event)) {
  13244. event.prevent();
  13245. }
  13246. });
  13247. const onFocusIn = bind(container, 'focusin', event => {
  13248. const stopped = settings.triggerEvent('focusin', event);
  13249. if (stopped) {
  13250. event.kill();
  13251. }
  13252. });
  13253. const focusoutTimeout = value$2();
  13254. const onFocusOut = bind(container, 'focusout', event => {
  13255. const stopped = settings.triggerEvent('focusout', event);
  13256. if (stopped) {
  13257. event.kill();
  13258. }
  13259. focusoutTimeout.set(setTimeout(() => {
  13260. settings.triggerEvent(postBlur(), event);
  13261. }, 0));
  13262. });
  13263. const unbind = () => {
  13264. each$1(simpleEvents, e => {
  13265. e.unbind();
  13266. });
  13267. onKeydown.unbind();
  13268. onFocusIn.unbind();
  13269. onFocusOut.unbind();
  13270. onPaste.unbind();
  13271. pasteTimeout.on(clearTimeout);
  13272. focusoutTimeout.on(clearTimeout);
  13273. };
  13274. return { unbind };
  13275. };
  13276. const derive = (rawEvent, rawTarget) => {
  13277. const source = get$g(rawEvent, 'target').getOr(rawTarget);
  13278. return Cell(source);
  13279. };
  13280. const fromSource = (event, source) => {
  13281. const stopper = Cell(false);
  13282. const cutter = Cell(false);
  13283. const stop = () => {
  13284. stopper.set(true);
  13285. };
  13286. const cut = () => {
  13287. cutter.set(true);
  13288. };
  13289. return {
  13290. stop,
  13291. cut,
  13292. isStopped: stopper.get,
  13293. isCut: cutter.get,
  13294. event,
  13295. setSource: source.set,
  13296. getSource: source.get
  13297. };
  13298. };
  13299. const fromExternal = event => {
  13300. const stopper = Cell(false);
  13301. const stop = () => {
  13302. stopper.set(true);
  13303. };
  13304. return {
  13305. stop,
  13306. cut: noop,
  13307. isStopped: stopper.get,
  13308. isCut: never,
  13309. event,
  13310. setSource: die('Cannot set source of a broadcasted event'),
  13311. getSource: die('Cannot get source of a broadcasted event')
  13312. };
  13313. };
  13314. const adt$1 = Adt.generate([
  13315. { stopped: [] },
  13316. { resume: ['element'] },
  13317. { complete: [] }
  13318. ]);
  13319. const doTriggerHandler = (lookup, eventType, rawEvent, target, source, logger) => {
  13320. const handler = lookup(eventType, target);
  13321. const simulatedEvent = fromSource(rawEvent, source);
  13322. return handler.fold(() => {
  13323. logger.logEventNoHandlers(eventType, target);
  13324. return adt$1.complete();
  13325. }, handlerInfo => {
  13326. const descHandler = handlerInfo.descHandler;
  13327. const eventHandler = getCurried(descHandler);
  13328. eventHandler(simulatedEvent);
  13329. if (simulatedEvent.isStopped()) {
  13330. logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
  13331. return adt$1.stopped();
  13332. } else if (simulatedEvent.isCut()) {
  13333. logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
  13334. return adt$1.complete();
  13335. } else {
  13336. return parent(handlerInfo.element).fold(() => {
  13337. logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
  13338. return adt$1.complete();
  13339. }, parent => {
  13340. logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
  13341. return adt$1.resume(parent);
  13342. });
  13343. }
  13344. });
  13345. };
  13346. const doTriggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, source, logger) => doTriggerHandler(lookup, eventType, rawEvent, rawTarget, source, logger).fold(always, parent => doTriggerOnUntilStopped(lookup, eventType, rawEvent, parent, source, logger), never);
  13347. const triggerHandler = (lookup, eventType, rawEvent, target, logger) => {
  13348. const source = derive(rawEvent, target);
  13349. return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger);
  13350. };
  13351. const broadcast = (listeners, rawEvent, _logger) => {
  13352. const simulatedEvent = fromExternal(rawEvent);
  13353. each$1(listeners, listener => {
  13354. const descHandler = listener.descHandler;
  13355. const handler = getCurried(descHandler);
  13356. handler(simulatedEvent);
  13357. });
  13358. return simulatedEvent.isStopped();
  13359. };
  13360. const triggerUntilStopped = (lookup, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger);
  13361. const triggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, logger) => {
  13362. const source = derive(rawEvent, rawTarget);
  13363. return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger);
  13364. };
  13365. const eventHandler = (element, descHandler) => ({
  13366. element,
  13367. descHandler
  13368. });
  13369. const broadcastHandler = (id, handler) => ({
  13370. id,
  13371. descHandler: handler
  13372. });
  13373. const EventRegistry = () => {
  13374. const registry = {};
  13375. const registerId = (extraArgs, id, events) => {
  13376. each(events, (v, k) => {
  13377. const handlers = registry[k] !== undefined ? registry[k] : {};
  13378. handlers[id] = curryArgs(v, extraArgs);
  13379. registry[k] = handlers;
  13380. });
  13381. };
  13382. const findHandler = (handlers, elem) => read$1(elem).bind(id => get$g(handlers, id)).map(descHandler => eventHandler(elem, descHandler));
  13383. const filterByType = type => get$g(registry, type).map(handlers => mapToArray(handlers, (f, id) => broadcastHandler(id, f))).getOr([]);
  13384. const find = (isAboveRoot, type, target) => get$g(registry, type).bind(handlers => closest$4(target, elem => findHandler(handlers, elem), isAboveRoot));
  13385. const unregisterId = id => {
  13386. each(registry, (handlersById, _eventName) => {
  13387. if (has$2(handlersById, id)) {
  13388. delete handlersById[id];
  13389. }
  13390. });
  13391. };
  13392. return {
  13393. registerId,
  13394. unregisterId,
  13395. filterByType,
  13396. find
  13397. };
  13398. };
  13399. const Registry = () => {
  13400. const events = EventRegistry();
  13401. const components = {};
  13402. const readOrTag = component => {
  13403. const elem = component.element;
  13404. return read$1(elem).getOrThunk(() => write('uid-', component.element));
  13405. };
  13406. const failOnDuplicate = (component, tagId) => {
  13407. const conflict = components[tagId];
  13408. if (conflict === component) {
  13409. unregister(component);
  13410. } else {
  13411. throw new Error('The tagId "' + tagId + '" is already used by: ' + element(conflict.element) + '\nCannot use it for: ' + element(component.element) + '\n' + 'The conflicting element is' + (inBody(conflict.element) ? ' ' : ' not ') + 'already in the DOM');
  13412. }
  13413. };
  13414. const register = component => {
  13415. const tagId = readOrTag(component);
  13416. if (hasNonNullableKey(components, tagId)) {
  13417. failOnDuplicate(component, tagId);
  13418. }
  13419. const extraArgs = [component];
  13420. events.registerId(extraArgs, tagId, component.events);
  13421. components[tagId] = component;
  13422. };
  13423. const unregister = component => {
  13424. read$1(component.element).each(tagId => {
  13425. delete components[tagId];
  13426. events.unregisterId(tagId);
  13427. });
  13428. };
  13429. const filter = type => events.filterByType(type);
  13430. const find = (isAboveRoot, type, target) => events.find(isAboveRoot, type, target);
  13431. const getById = id => get$g(components, id);
  13432. return {
  13433. find,
  13434. filter,
  13435. register,
  13436. unregister,
  13437. getById
  13438. };
  13439. };
  13440. const factory$j = detail => {
  13441. const {attributes, ...domWithoutAttributes} = detail.dom;
  13442. return {
  13443. uid: detail.uid,
  13444. dom: {
  13445. tag: 'div',
  13446. attributes: {
  13447. role: 'presentation',
  13448. ...attributes
  13449. },
  13450. ...domWithoutAttributes
  13451. },
  13452. components: detail.components,
  13453. behaviours: get$3(detail.containerBehaviours),
  13454. events: detail.events,
  13455. domModification: detail.domModification,
  13456. eventOrder: detail.eventOrder
  13457. };
  13458. };
  13459. const Container = single({
  13460. name: 'Container',
  13461. factory: factory$j,
  13462. configFields: [
  13463. defaulted('components', []),
  13464. field('containerBehaviours', []),
  13465. defaulted('events', {}),
  13466. defaulted('domModification', {}),
  13467. defaulted('eventOrder', {})
  13468. ]
  13469. });
  13470. const takeover = root => {
  13471. const isAboveRoot = el => parent(root.element).fold(always, parent => eq(el, parent));
  13472. const registry = Registry();
  13473. const lookup = (eventName, target) => registry.find(isAboveRoot, eventName, target);
  13474. const domEvents = setup$d(root.element, {
  13475. triggerEvent: (eventName, event) => {
  13476. return monitorEvent(eventName, event.target, logger => triggerUntilStopped(lookup, eventName, event, logger));
  13477. }
  13478. });
  13479. const systemApi = {
  13480. debugInfo: constant$1('real'),
  13481. triggerEvent: (eventName, target, data) => {
  13482. monitorEvent(eventName, target, logger => triggerOnUntilStopped(lookup, eventName, data, target, logger));
  13483. },
  13484. triggerFocus: (target, originator) => {
  13485. read$1(target).fold(() => {
  13486. focus$3(target);
  13487. }, _alloyId => {
  13488. monitorEvent(focus$4(), target, logger => {
  13489. triggerHandler(lookup, focus$4(), {
  13490. originator,
  13491. kill: noop,
  13492. prevent: noop,
  13493. target
  13494. }, target, logger);
  13495. return false;
  13496. });
  13497. });
  13498. },
  13499. triggerEscape: (comp, simulatedEvent) => {
  13500. systemApi.triggerEvent('keydown', comp.element, simulatedEvent.event);
  13501. },
  13502. getByUid: uid => {
  13503. return getByUid(uid);
  13504. },
  13505. getByDom: elem => {
  13506. return getByDom(elem);
  13507. },
  13508. build: build$1,
  13509. buildOrPatch: buildOrPatch,
  13510. addToGui: c => {
  13511. add(c);
  13512. },
  13513. removeFromGui: c => {
  13514. remove(c);
  13515. },
  13516. addToWorld: c => {
  13517. addToWorld(c);
  13518. },
  13519. removeFromWorld: c => {
  13520. removeFromWorld(c);
  13521. },
  13522. broadcast: message => {
  13523. broadcast$1(message);
  13524. },
  13525. broadcastOn: (channels, message) => {
  13526. broadcastOn(channels, message);
  13527. },
  13528. broadcastEvent: (eventName, event) => {
  13529. broadcastEvent(eventName, event);
  13530. },
  13531. isConnected: always
  13532. };
  13533. const addToWorld = component => {
  13534. component.connect(systemApi);
  13535. if (!isText(component.element)) {
  13536. registry.register(component);
  13537. each$1(component.components(), addToWorld);
  13538. systemApi.triggerEvent(systemInit(), component.element, { target: component.element });
  13539. }
  13540. };
  13541. const removeFromWorld = component => {
  13542. if (!isText(component.element)) {
  13543. each$1(component.components(), removeFromWorld);
  13544. registry.unregister(component);
  13545. }
  13546. component.disconnect();
  13547. };
  13548. const add = component => {
  13549. attach(root, component);
  13550. };
  13551. const remove = component => {
  13552. detach(component);
  13553. };
  13554. const destroy = () => {
  13555. domEvents.unbind();
  13556. remove$5(root.element);
  13557. };
  13558. const broadcastData = data => {
  13559. const receivers = registry.filter(receive());
  13560. each$1(receivers, receiver => {
  13561. const descHandler = receiver.descHandler;
  13562. const handler = getCurried(descHandler);
  13563. handler(data);
  13564. });
  13565. };
  13566. const broadcast$1 = message => {
  13567. broadcastData({
  13568. universal: true,
  13569. data: message
  13570. });
  13571. };
  13572. const broadcastOn = (channels, message) => {
  13573. broadcastData({
  13574. universal: false,
  13575. channels,
  13576. data: message
  13577. });
  13578. };
  13579. const broadcastEvent = (eventName, event) => {
  13580. const listeners = registry.filter(eventName);
  13581. return broadcast(listeners, event);
  13582. };
  13583. const getByUid = uid => registry.getById(uid).fold(() => Result.error(new Error('Could not find component with uid: "' + uid + '" in system.')), Result.value);
  13584. const getByDom = elem => {
  13585. const uid = read$1(elem).getOr('not found');
  13586. return getByUid(uid);
  13587. };
  13588. addToWorld(root);
  13589. return {
  13590. root,
  13591. element: root.element,
  13592. destroy,
  13593. add,
  13594. remove,
  13595. getByUid,
  13596. getByDom,
  13597. addToWorld,
  13598. removeFromWorld,
  13599. broadcast: broadcast$1,
  13600. broadcastOn,
  13601. broadcastEvent
  13602. };
  13603. };
  13604. const renderBar = (spec, backstage) => ({
  13605. dom: {
  13606. tag: 'div',
  13607. classes: [
  13608. 'tox-bar',
  13609. 'tox-form__controls-h-stack'
  13610. ]
  13611. },
  13612. components: map$2(spec.items, backstage.interpreter)
  13613. });
  13614. const schema$j = constant$1([
  13615. defaulted('prefix', 'form-field'),
  13616. field('fieldBehaviours', [
  13617. Composing,
  13618. Representing
  13619. ])
  13620. ]);
  13621. const parts$d = constant$1([
  13622. optional({
  13623. schema: [required$1('dom')],
  13624. name: 'label'
  13625. }),
  13626. optional({
  13627. factory: {
  13628. sketch: spec => {
  13629. return {
  13630. uid: spec.uid,
  13631. dom: {
  13632. tag: 'span',
  13633. styles: { display: 'none' },
  13634. attributes: { 'aria-hidden': 'true' },
  13635. innerHtml: spec.text
  13636. }
  13637. };
  13638. }
  13639. },
  13640. schema: [required$1('text')],
  13641. name: 'aria-descriptor'
  13642. }),
  13643. required({
  13644. factory: {
  13645. sketch: spec => {
  13646. const excludeFactory = exclude(spec, ['factory']);
  13647. return spec.factory.sketch(excludeFactory);
  13648. }
  13649. },
  13650. schema: [required$1('factory')],
  13651. name: 'field'
  13652. })
  13653. ]);
  13654. const factory$i = (detail, components, _spec, _externals) => {
  13655. const behaviours = augment(detail.fieldBehaviours, [
  13656. Composing.config({
  13657. find: container => {
  13658. return getPart(container, detail, 'field');
  13659. }
  13660. }),
  13661. Representing.config({
  13662. store: {
  13663. mode: 'manual',
  13664. getValue: field => {
  13665. return Composing.getCurrent(field).bind(Representing.getValue);
  13666. },
  13667. setValue: (field, value) => {
  13668. Composing.getCurrent(field).each(current => {
  13669. Representing.setValue(current, value);
  13670. });
  13671. }
  13672. }
  13673. })
  13674. ]);
  13675. const events = derive$2([runOnAttached((component, _simulatedEvent) => {
  13676. const ps = getParts(component, detail, [
  13677. 'label',
  13678. 'field',
  13679. 'aria-descriptor'
  13680. ]);
  13681. ps.field().each(field => {
  13682. const id = generate$6(detail.prefix);
  13683. ps.label().each(label => {
  13684. set$9(label.element, 'for', id);
  13685. set$9(field.element, 'id', id);
  13686. });
  13687. ps['aria-descriptor']().each(descriptor => {
  13688. const descriptorId = generate$6(detail.prefix);
  13689. set$9(descriptor.element, 'id', descriptorId);
  13690. set$9(field.element, 'aria-describedby', descriptorId);
  13691. });
  13692. });
  13693. })]);
  13694. const apis = {
  13695. getField: container => getPart(container, detail, 'field'),
  13696. getLabel: container => getPart(container, detail, 'label')
  13697. };
  13698. return {
  13699. uid: detail.uid,
  13700. dom: detail.dom,
  13701. components,
  13702. behaviours,
  13703. events,
  13704. apis
  13705. };
  13706. };
  13707. const FormField = composite({
  13708. name: 'FormField',
  13709. configFields: schema$j(),
  13710. partFields: parts$d(),
  13711. factory: factory$i,
  13712. apis: {
  13713. getField: (apis, comp) => apis.getField(comp),
  13714. getLabel: (apis, comp) => apis.getLabel(comp)
  13715. }
  13716. });
  13717. const exhibit$2 = (base, tabConfig) => nu$7({
  13718. attributes: wrapAll([{
  13719. key: tabConfig.tabAttr,
  13720. value: 'true'
  13721. }])
  13722. });
  13723. var ActiveTabstopping = /*#__PURE__*/Object.freeze({
  13724. __proto__: null,
  13725. exhibit: exhibit$2
  13726. });
  13727. var TabstopSchema = [defaulted('tabAttr', 'data-alloy-tabstop')];
  13728. const Tabstopping = create$4({
  13729. fields: TabstopSchema,
  13730. name: 'tabstopping',
  13731. active: ActiveTabstopping
  13732. });
  13733. var global$3 = tinymce.util.Tools.resolve('tinymce.html.Entities');
  13734. const renderFormFieldWith = (pLabel, pField, extraClasses, extraBehaviours) => {
  13735. const spec = renderFormFieldSpecWith(pLabel, pField, extraClasses, extraBehaviours);
  13736. return FormField.sketch(spec);
  13737. };
  13738. const renderFormField = (pLabel, pField) => renderFormFieldWith(pLabel, pField, [], []);
  13739. const renderFormFieldSpecWith = (pLabel, pField, extraClasses, extraBehaviours) => ({
  13740. dom: renderFormFieldDomWith(extraClasses),
  13741. components: pLabel.toArray().concat([pField]),
  13742. fieldBehaviours: derive$1(extraBehaviours)
  13743. });
  13744. const renderFormFieldDom = () => renderFormFieldDomWith([]);
  13745. const renderFormFieldDomWith = extraClasses => ({
  13746. tag: 'div',
  13747. classes: ['tox-form__group'].concat(extraClasses)
  13748. });
  13749. const renderLabel$3 = (label, providersBackstage) => FormField.parts.label({
  13750. dom: {
  13751. tag: 'label',
  13752. classes: ['tox-label']
  13753. },
  13754. components: [text$2(providersBackstage.translate(label))]
  13755. });
  13756. const formChangeEvent = generate$6('form-component-change');
  13757. const formCloseEvent = generate$6('form-close');
  13758. const formCancelEvent = generate$6('form-cancel');
  13759. const formActionEvent = generate$6('form-action');
  13760. const formSubmitEvent = generate$6('form-submit');
  13761. const formBlockEvent = generate$6('form-block');
  13762. const formUnblockEvent = generate$6('form-unblock');
  13763. const formTabChangeEvent = generate$6('form-tabchange');
  13764. const formResizeEvent = generate$6('form-resize');
  13765. const renderCollection = (spec, providersBackstage, initialData) => {
  13766. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  13767. const icons = providersBackstage.icons();
  13768. const getIcon = icon => {
  13769. var _a;
  13770. return (_a = icons[icon]) !== null && _a !== void 0 ? _a : icon;
  13771. };
  13772. const runOnItem = f => (comp, se) => {
  13773. closest$1(se.event.target, '[data-collection-item-value]').each(target => {
  13774. f(comp, se, target, get$f(target, 'data-collection-item-value'));
  13775. });
  13776. };
  13777. const setContents = (comp, items) => {
  13778. const htmlLines = map$2(items, item => {
  13779. const itemText = global$8.translate(item.text);
  13780. const textContent = spec.columns === 1 ? `<div class="tox-collection__item-label">${ itemText }</div>` : '';
  13781. const iconContent = `<div class="tox-collection__item-icon">${ getIcon(item.icon) }</div>`;
  13782. const mapItemName = {
  13783. '_': ' ',
  13784. ' - ': ' ',
  13785. '-': ' '
  13786. };
  13787. const ariaLabel = itemText.replace(/\_| \- |\-/g, match => mapItemName[match]);
  13788. const disabledClass = providersBackstage.isDisabled() ? ' tox-collection__item--state-disabled' : '';
  13789. return `<div class="tox-collection__item${ disabledClass }" tabindex="-1" data-collection-item-value="${ global$3.encodeAllRaw(item.value) }" title="${ ariaLabel }" aria-label="${ ariaLabel }">${ iconContent }${ textContent }</div>`;
  13790. });
  13791. const chunks = spec.columns !== 'auto' && spec.columns > 1 ? chunk$1(htmlLines, spec.columns) : [htmlLines];
  13792. const html = map$2(chunks, ch => `<div class="tox-collection__group">${ ch.join('') }</div>`);
  13793. set$6(comp.element, html.join(''));
  13794. };
  13795. const onClick = runOnItem((comp, se, tgt, itemValue) => {
  13796. se.stop();
  13797. if (!providersBackstage.isDisabled()) {
  13798. emitWith(comp, formActionEvent, {
  13799. name: spec.name,
  13800. value: itemValue
  13801. });
  13802. }
  13803. });
  13804. const collectionEvents = [
  13805. run$1(mouseover(), runOnItem((comp, se, tgt) => {
  13806. focus$3(tgt);
  13807. })),
  13808. run$1(click(), onClick),
  13809. run$1(tap(), onClick),
  13810. run$1(focusin(), runOnItem((comp, se, tgt) => {
  13811. descendant(comp.element, '.' + activeClass).each(currentActive => {
  13812. remove$2(currentActive, activeClass);
  13813. });
  13814. add$2(tgt, activeClass);
  13815. })),
  13816. run$1(focusout(), runOnItem(comp => {
  13817. descendant(comp.element, '.' + activeClass).each(currentActive => {
  13818. remove$2(currentActive, activeClass);
  13819. });
  13820. })),
  13821. runOnExecute$1(runOnItem((comp, se, tgt, itemValue) => {
  13822. emitWith(comp, formActionEvent, {
  13823. name: spec.name,
  13824. value: itemValue
  13825. });
  13826. }))
  13827. ];
  13828. const iterCollectionItems = (comp, applyAttributes) => map$2(descendants(comp.element, '.tox-collection__item'), applyAttributes);
  13829. const pField = FormField.parts.field({
  13830. dom: {
  13831. tag: 'div',
  13832. classes: ['tox-collection'].concat(spec.columns !== 1 ? ['tox-collection--grid'] : ['tox-collection--list'])
  13833. },
  13834. components: [],
  13835. factory: { sketch: identity },
  13836. behaviours: derive$1([
  13837. Disabling.config({
  13838. disabled: providersBackstage.isDisabled,
  13839. onDisabled: comp => {
  13840. iterCollectionItems(comp, childElm => {
  13841. add$2(childElm, 'tox-collection__item--state-disabled');
  13842. set$9(childElm, 'aria-disabled', true);
  13843. });
  13844. },
  13845. onEnabled: comp => {
  13846. iterCollectionItems(comp, childElm => {
  13847. remove$2(childElm, 'tox-collection__item--state-disabled');
  13848. remove$7(childElm, 'aria-disabled');
  13849. });
  13850. }
  13851. }),
  13852. receivingConfig(),
  13853. Replacing.config({}),
  13854. Representing.config({
  13855. store: {
  13856. mode: 'memory',
  13857. initialValue: initialData.getOr([])
  13858. },
  13859. onSetValue: (comp, items) => {
  13860. setContents(comp, items);
  13861. if (spec.columns === 'auto') {
  13862. detectSize(comp, 5, 'tox-collection__item').each(({numRows, numColumns}) => {
  13863. Keying.setGridSize(comp, numRows, numColumns);
  13864. });
  13865. }
  13866. emit(comp, formResizeEvent);
  13867. }
  13868. }),
  13869. Tabstopping.config({}),
  13870. Keying.config(deriveCollectionMovement(spec.columns, 'normal')),
  13871. config('collection-events', collectionEvents)
  13872. ]),
  13873. eventOrder: {
  13874. [execute$5()]: [
  13875. 'disabling',
  13876. 'alloy.base.behaviour',
  13877. 'collection-events'
  13878. ]
  13879. }
  13880. });
  13881. const extraClasses = ['tox-form__group--collection'];
  13882. return renderFormFieldWith(pLabel, pField, extraClasses, []);
  13883. };
  13884. const ariaElements = [
  13885. 'input',
  13886. 'textarea'
  13887. ];
  13888. const isAriaElement = elem => {
  13889. const name = name$3(elem);
  13890. return contains$2(ariaElements, name);
  13891. };
  13892. const markValid = (component, invalidConfig) => {
  13893. const elem = invalidConfig.getRoot(component).getOr(component.element);
  13894. remove$2(elem, invalidConfig.invalidClass);
  13895. invalidConfig.notify.each(notifyInfo => {
  13896. if (isAriaElement(component.element)) {
  13897. set$9(component.element, 'aria-invalid', false);
  13898. }
  13899. notifyInfo.getContainer(component).each(container => {
  13900. set$6(container, notifyInfo.validHtml);
  13901. });
  13902. notifyInfo.onValid(component);
  13903. });
  13904. };
  13905. const markInvalid = (component, invalidConfig, invalidState, text) => {
  13906. const elem = invalidConfig.getRoot(component).getOr(component.element);
  13907. add$2(elem, invalidConfig.invalidClass);
  13908. invalidConfig.notify.each(notifyInfo => {
  13909. if (isAriaElement(component.element)) {
  13910. set$9(component.element, 'aria-invalid', true);
  13911. }
  13912. notifyInfo.getContainer(component).each(container => {
  13913. set$6(container, text);
  13914. });
  13915. notifyInfo.onInvalid(component, text);
  13916. });
  13917. };
  13918. const query = (component, invalidConfig, _invalidState) => invalidConfig.validator.fold(() => Future.pure(Result.value(true)), validatorInfo => validatorInfo.validate(component));
  13919. const run = (component, invalidConfig, invalidState) => {
  13920. invalidConfig.notify.each(notifyInfo => {
  13921. notifyInfo.onValidate(component);
  13922. });
  13923. return query(component, invalidConfig).map(valid => {
  13924. if (component.getSystem().isConnected()) {
  13925. return valid.fold(err => {
  13926. markInvalid(component, invalidConfig, invalidState, err);
  13927. return Result.error(err);
  13928. }, v => {
  13929. markValid(component, invalidConfig);
  13930. return Result.value(v);
  13931. });
  13932. } else {
  13933. return Result.error('No longer in system');
  13934. }
  13935. });
  13936. };
  13937. const isInvalid = (component, invalidConfig) => {
  13938. const elem = invalidConfig.getRoot(component).getOr(component.element);
  13939. return has(elem, invalidConfig.invalidClass);
  13940. };
  13941. var InvalidateApis = /*#__PURE__*/Object.freeze({
  13942. __proto__: null,
  13943. markValid: markValid,
  13944. markInvalid: markInvalid,
  13945. query: query,
  13946. run: run,
  13947. isInvalid: isInvalid
  13948. });
  13949. const events$8 = (invalidConfig, invalidState) => invalidConfig.validator.map(validatorInfo => derive$2([run$1(validatorInfo.onEvent, component => {
  13950. run(component, invalidConfig, invalidState).get(identity);
  13951. })].concat(validatorInfo.validateOnLoad ? [runOnAttached(component => {
  13952. run(component, invalidConfig, invalidState).get(noop);
  13953. })] : []))).getOr({});
  13954. var ActiveInvalidate = /*#__PURE__*/Object.freeze({
  13955. __proto__: null,
  13956. events: events$8
  13957. });
  13958. var InvalidateSchema = [
  13959. required$1('invalidClass'),
  13960. defaulted('getRoot', Optional.none),
  13961. optionObjOf('notify', [
  13962. defaulted('aria', 'alert'),
  13963. defaulted('getContainer', Optional.none),
  13964. defaulted('validHtml', ''),
  13965. onHandler('onValid'),
  13966. onHandler('onInvalid'),
  13967. onHandler('onValidate')
  13968. ]),
  13969. optionObjOf('validator', [
  13970. required$1('validate'),
  13971. defaulted('onEvent', 'input'),
  13972. defaulted('validateOnLoad', true)
  13973. ])
  13974. ];
  13975. const Invalidating = create$4({
  13976. fields: InvalidateSchema,
  13977. name: 'invalidating',
  13978. active: ActiveInvalidate,
  13979. apis: InvalidateApis,
  13980. extra: {
  13981. validation: validator => {
  13982. return component => {
  13983. const v = Representing.getValue(component);
  13984. return Future.pure(validator(v));
  13985. };
  13986. }
  13987. }
  13988. });
  13989. const exhibit$1 = () => nu$7({
  13990. styles: {
  13991. '-webkit-user-select': 'none',
  13992. 'user-select': 'none',
  13993. '-ms-user-select': 'none',
  13994. '-moz-user-select': '-moz-none'
  13995. },
  13996. attributes: { unselectable: 'on' }
  13997. });
  13998. const events$7 = () => derive$2([abort(selectstart(), always)]);
  13999. var ActiveUnselecting = /*#__PURE__*/Object.freeze({
  14000. __proto__: null,
  14001. events: events$7,
  14002. exhibit: exhibit$1
  14003. });
  14004. const Unselecting = create$4({
  14005. fields: [],
  14006. name: 'unselecting',
  14007. active: ActiveUnselecting
  14008. });
  14009. const renderPanelButton = (spec, sharedBackstage) => Dropdown.sketch({
  14010. dom: spec.dom,
  14011. components: spec.components,
  14012. toggleClass: 'mce-active',
  14013. dropdownBehaviours: derive$1([
  14014. DisablingConfigs.button(sharedBackstage.providers.isDisabled),
  14015. receivingConfig(),
  14016. Unselecting.config({}),
  14017. Tabstopping.config({})
  14018. ]),
  14019. layouts: spec.layouts,
  14020. sandboxClasses: ['tox-dialog__popups'],
  14021. lazySink: sharedBackstage.getSink,
  14022. fetch: comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
  14023. spec.onItemAction(comp, value);
  14024. }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, sharedBackstage.providers), { movement: deriveMenuMovement(spec.columns, spec.presets) })))),
  14025. parts: { menu: part(false, 1, spec.presets) }
  14026. });
  14027. const colorInputChangeEvent = generate$6('color-input-change');
  14028. const colorSwatchChangeEvent = generate$6('color-swatch-change');
  14029. const colorPickerCancelEvent = generate$6('color-picker-cancel');
  14030. const renderColorInput = (spec, sharedBackstage, colorInputBackstage, initialData) => {
  14031. const pField = FormField.parts.field({
  14032. factory: Input,
  14033. inputClasses: ['tox-textfield'],
  14034. data: initialData,
  14035. onSetValue: c => Invalidating.run(c).get(noop),
  14036. inputBehaviours: derive$1([
  14037. Disabling.config({ disabled: sharedBackstage.providers.isDisabled }),
  14038. receivingConfig(),
  14039. Tabstopping.config({}),
  14040. Invalidating.config({
  14041. invalidClass: 'tox-textbox-field-invalid',
  14042. getRoot: comp => parentElement(comp.element),
  14043. notify: {
  14044. onValid: comp => {
  14045. const val = Representing.getValue(comp);
  14046. emitWith(comp, colorInputChangeEvent, { color: val });
  14047. }
  14048. },
  14049. validator: {
  14050. validateOnLoad: false,
  14051. validate: input => {
  14052. const inputValue = Representing.getValue(input);
  14053. if (inputValue.length === 0) {
  14054. return Future.pure(Result.value(true));
  14055. } else {
  14056. const span = SugarElement.fromTag('span');
  14057. set$8(span, 'background-color', inputValue);
  14058. const res = getRaw(span, 'background-color').fold(() => Result.error('blah'), _ => Result.value(inputValue));
  14059. return Future.pure(res);
  14060. }
  14061. }
  14062. }
  14063. })
  14064. ]),
  14065. selectOnFocus: false
  14066. });
  14067. const pLabel = spec.label.map(label => renderLabel$3(label, sharedBackstage.providers));
  14068. const emitSwatchChange = (colorBit, value) => {
  14069. emitWith(colorBit, colorSwatchChangeEvent, { value });
  14070. };
  14071. const onItemAction = (comp, value) => {
  14072. memColorButton.getOpt(comp).each(colorBit => {
  14073. if (value === 'custom') {
  14074. colorInputBackstage.colorPicker(valueOpt => {
  14075. valueOpt.fold(() => emit(colorBit, colorPickerCancelEvent), value => {
  14076. emitSwatchChange(colorBit, value);
  14077. addColor(spec.storageKey, value);
  14078. });
  14079. }, '#ffffff');
  14080. } else if (value === 'remove') {
  14081. emitSwatchChange(colorBit, '');
  14082. } else {
  14083. emitSwatchChange(colorBit, value);
  14084. }
  14085. });
  14086. };
  14087. const memColorButton = record(renderPanelButton({
  14088. dom: {
  14089. tag: 'span',
  14090. attributes: { 'aria-label': sharedBackstage.providers.translate('Color swatch') }
  14091. },
  14092. layouts: {
  14093. onRtl: () => [
  14094. southwest$2,
  14095. southeast$2,
  14096. south$2
  14097. ],
  14098. onLtr: () => [
  14099. southeast$2,
  14100. southwest$2,
  14101. south$2
  14102. ]
  14103. },
  14104. components: [],
  14105. fetch: getFetch$1(colorInputBackstage.getColors(spec.storageKey), spec.storageKey, colorInputBackstage.hasCustomColors()),
  14106. columns: colorInputBackstage.getColorCols(spec.storageKey),
  14107. presets: 'color',
  14108. onItemAction
  14109. }, sharedBackstage));
  14110. return FormField.sketch({
  14111. dom: {
  14112. tag: 'div',
  14113. classes: ['tox-form__group']
  14114. },
  14115. components: pLabel.toArray().concat([{
  14116. dom: {
  14117. tag: 'div',
  14118. classes: ['tox-color-input']
  14119. },
  14120. components: [
  14121. pField,
  14122. memColorButton.asSpec()
  14123. ]
  14124. }]),
  14125. fieldBehaviours: derive$1([config('form-field-events', [
  14126. run$1(colorInputChangeEvent, (comp, se) => {
  14127. memColorButton.getOpt(comp).each(colorButton => {
  14128. set$8(colorButton.element, 'background-color', se.event.color);
  14129. });
  14130. emitWith(comp, formChangeEvent, { name: spec.name });
  14131. }),
  14132. run$1(colorSwatchChangeEvent, (comp, se) => {
  14133. FormField.getField(comp).each(field => {
  14134. Representing.setValue(field, se.event.value);
  14135. Composing.getCurrent(comp).each(Focusing.focus);
  14136. });
  14137. }),
  14138. run$1(colorPickerCancelEvent, (comp, _se) => {
  14139. FormField.getField(comp).each(_field => {
  14140. Composing.getCurrent(comp).each(Focusing.focus);
  14141. });
  14142. })
  14143. ])])
  14144. });
  14145. };
  14146. const labelPart = optional({
  14147. schema: [required$1('dom')],
  14148. name: 'label'
  14149. });
  14150. const edgePart = name => optional({
  14151. name: '' + name + '-edge',
  14152. overrides: detail => {
  14153. const action = detail.model.manager.edgeActions[name];
  14154. return action.fold(() => ({}), a => ({
  14155. events: derive$2([
  14156. runActionExtra(touchstart(), (comp, se, d) => a(comp, d), [detail]),
  14157. runActionExtra(mousedown(), (comp, se, d) => a(comp, d), [detail]),
  14158. runActionExtra(mousemove(), (comp, se, det) => {
  14159. if (det.mouseIsDown.get()) {
  14160. a(comp, det);
  14161. }
  14162. }, [detail])
  14163. ])
  14164. }));
  14165. }
  14166. });
  14167. const tlEdgePart = edgePart('top-left');
  14168. const tedgePart = edgePart('top');
  14169. const trEdgePart = edgePart('top-right');
  14170. const redgePart = edgePart('right');
  14171. const brEdgePart = edgePart('bottom-right');
  14172. const bedgePart = edgePart('bottom');
  14173. const blEdgePart = edgePart('bottom-left');
  14174. const ledgePart = edgePart('left');
  14175. const thumbPart = required({
  14176. name: 'thumb',
  14177. defaults: constant$1({ dom: { styles: { position: 'absolute' } } }),
  14178. overrides: detail => {
  14179. return {
  14180. events: derive$2([
  14181. redirectToPart(touchstart(), detail, 'spectrum'),
  14182. redirectToPart(touchmove(), detail, 'spectrum'),
  14183. redirectToPart(touchend(), detail, 'spectrum'),
  14184. redirectToPart(mousedown(), detail, 'spectrum'),
  14185. redirectToPart(mousemove(), detail, 'spectrum'),
  14186. redirectToPart(mouseup(), detail, 'spectrum')
  14187. ])
  14188. };
  14189. }
  14190. });
  14191. const isShift = event => isShift$1(event.event);
  14192. const spectrumPart = required({
  14193. schema: [customField('mouseIsDown', () => Cell(false))],
  14194. name: 'spectrum',
  14195. overrides: detail => {
  14196. const modelDetail = detail.model;
  14197. const model = modelDetail.manager;
  14198. const setValueFrom = (component, simulatedEvent) => model.getValueFromEvent(simulatedEvent).map(value => model.setValueFrom(component, detail, value));
  14199. return {
  14200. behaviours: derive$1([
  14201. Keying.config({
  14202. mode: 'special',
  14203. onLeft: (spectrum, event) => model.onLeft(spectrum, detail, isShift(event)),
  14204. onRight: (spectrum, event) => model.onRight(spectrum, detail, isShift(event)),
  14205. onUp: (spectrum, event) => model.onUp(spectrum, detail, isShift(event)),
  14206. onDown: (spectrum, event) => model.onDown(spectrum, detail, isShift(event))
  14207. }),
  14208. Tabstopping.config({}),
  14209. Focusing.config({})
  14210. ]),
  14211. events: derive$2([
  14212. run$1(touchstart(), setValueFrom),
  14213. run$1(touchmove(), setValueFrom),
  14214. run$1(mousedown(), setValueFrom),
  14215. run$1(mousemove(), (spectrum, se) => {
  14216. if (detail.mouseIsDown.get()) {
  14217. setValueFrom(spectrum, se);
  14218. }
  14219. })
  14220. ])
  14221. };
  14222. }
  14223. });
  14224. var SliderParts = [
  14225. labelPart,
  14226. ledgePart,
  14227. redgePart,
  14228. tedgePart,
  14229. bedgePart,
  14230. tlEdgePart,
  14231. trEdgePart,
  14232. blEdgePart,
  14233. brEdgePart,
  14234. thumbPart,
  14235. spectrumPart
  14236. ];
  14237. const _sliderChangeEvent = 'slider.change.value';
  14238. const sliderChangeEvent = constant$1(_sliderChangeEvent);
  14239. const isTouchEvent$2 = evt => evt.type.indexOf('touch') !== -1;
  14240. const getEventSource = simulatedEvent => {
  14241. const evt = simulatedEvent.event.raw;
  14242. if (isTouchEvent$2(evt)) {
  14243. const touchEvent = evt;
  14244. return touchEvent.touches !== undefined && touchEvent.touches.length === 1 ? Optional.some(touchEvent.touches[0]).map(t => SugarPosition(t.clientX, t.clientY)) : Optional.none();
  14245. } else {
  14246. const mouseEvent = evt;
  14247. return mouseEvent.clientX !== undefined ? Optional.some(mouseEvent).map(me => SugarPosition(me.clientX, me.clientY)) : Optional.none();
  14248. }
  14249. };
  14250. const t = 'top', r = 'right', b = 'bottom', l = 'left';
  14251. const minX = detail => detail.model.minX;
  14252. const minY = detail => detail.model.minY;
  14253. const min1X = detail => detail.model.minX - 1;
  14254. const min1Y = detail => detail.model.minY - 1;
  14255. const maxX = detail => detail.model.maxX;
  14256. const maxY = detail => detail.model.maxY;
  14257. const max1X = detail => detail.model.maxX + 1;
  14258. const max1Y = detail => detail.model.maxY + 1;
  14259. const range = (detail, max, min) => max(detail) - min(detail);
  14260. const xRange = detail => range(detail, maxX, minX);
  14261. const yRange = detail => range(detail, maxY, minY);
  14262. const halfX = detail => xRange(detail) / 2;
  14263. const halfY = detail => yRange(detail) / 2;
  14264. const step = (detail, useMultiplier) => useMultiplier ? detail.stepSize * detail.speedMultiplier : detail.stepSize;
  14265. const snap = detail => detail.snapToGrid;
  14266. const snapStart = detail => detail.snapStart;
  14267. const rounded = detail => detail.rounded;
  14268. const hasEdge = (detail, edgeName) => detail[edgeName + '-edge'] !== undefined;
  14269. const hasLEdge = detail => hasEdge(detail, l);
  14270. const hasREdge = detail => hasEdge(detail, r);
  14271. const hasTEdge = detail => hasEdge(detail, t);
  14272. const hasBEdge = detail => hasEdge(detail, b);
  14273. const currentValue = detail => detail.model.value.get();
  14274. const xyValue = (x, y) => ({
  14275. x,
  14276. y
  14277. });
  14278. const fireSliderChange$3 = (component, value) => {
  14279. emitWith(component, sliderChangeEvent(), { value });
  14280. };
  14281. const setToTLEdgeXY = (edge, detail) => {
  14282. fireSliderChange$3(edge, xyValue(min1X(detail), min1Y(detail)));
  14283. };
  14284. const setToTEdge = (edge, detail) => {
  14285. fireSliderChange$3(edge, min1Y(detail));
  14286. };
  14287. const setToTEdgeXY = (edge, detail) => {
  14288. fireSliderChange$3(edge, xyValue(halfX(detail), min1Y(detail)));
  14289. };
  14290. const setToTREdgeXY = (edge, detail) => {
  14291. fireSliderChange$3(edge, xyValue(max1X(detail), min1Y(detail)));
  14292. };
  14293. const setToREdge = (edge, detail) => {
  14294. fireSliderChange$3(edge, max1X(detail));
  14295. };
  14296. const setToREdgeXY = (edge, detail) => {
  14297. fireSliderChange$3(edge, xyValue(max1X(detail), halfY(detail)));
  14298. };
  14299. const setToBREdgeXY = (edge, detail) => {
  14300. fireSliderChange$3(edge, xyValue(max1X(detail), max1Y(detail)));
  14301. };
  14302. const setToBEdge = (edge, detail) => {
  14303. fireSliderChange$3(edge, max1Y(detail));
  14304. };
  14305. const setToBEdgeXY = (edge, detail) => {
  14306. fireSliderChange$3(edge, xyValue(halfX(detail), max1Y(detail)));
  14307. };
  14308. const setToBLEdgeXY = (edge, detail) => {
  14309. fireSliderChange$3(edge, xyValue(min1X(detail), max1Y(detail)));
  14310. };
  14311. const setToLEdge = (edge, detail) => {
  14312. fireSliderChange$3(edge, min1X(detail));
  14313. };
  14314. const setToLEdgeXY = (edge, detail) => {
  14315. fireSliderChange$3(edge, xyValue(min1X(detail), halfY(detail)));
  14316. };
  14317. const reduceBy = (value, min, max, step) => {
  14318. if (value < min) {
  14319. return value;
  14320. } else if (value > max) {
  14321. return max;
  14322. } else if (value === min) {
  14323. return min - 1;
  14324. } else {
  14325. return Math.max(min, value - step);
  14326. }
  14327. };
  14328. const increaseBy = (value, min, max, step) => {
  14329. if (value > max) {
  14330. return value;
  14331. } else if (value < min) {
  14332. return min;
  14333. } else if (value === max) {
  14334. return max + 1;
  14335. } else {
  14336. return Math.min(max, value + step);
  14337. }
  14338. };
  14339. const capValue = (value, min, max) => Math.max(min, Math.min(max, value));
  14340. const snapValueOf = (value, min, max, step, snapStart) => snapStart.fold(() => {
  14341. const initValue = value - min;
  14342. const extraValue = Math.round(initValue / step) * step;
  14343. return capValue(min + extraValue, min - 1, max + 1);
  14344. }, start => {
  14345. const remainder = (value - start) % step;
  14346. const adjustment = Math.round(remainder / step);
  14347. const rawSteps = Math.floor((value - start) / step);
  14348. const maxSteps = Math.floor((max - start) / step);
  14349. const numSteps = Math.min(maxSteps, rawSteps + adjustment);
  14350. const r = start + numSteps * step;
  14351. return Math.max(start, r);
  14352. });
  14353. const findOffsetOf = (value, min, max) => Math.min(max, Math.max(value, min)) - min;
  14354. const findValueOf = args => {
  14355. const {min, max, range, value, step, snap, snapStart, rounded, hasMinEdge, hasMaxEdge, minBound, maxBound, screenRange} = args;
  14356. const capMin = hasMinEdge ? min - 1 : min;
  14357. const capMax = hasMaxEdge ? max + 1 : max;
  14358. if (value < minBound) {
  14359. return capMin;
  14360. } else if (value > maxBound) {
  14361. return capMax;
  14362. } else {
  14363. const offset = findOffsetOf(value, minBound, maxBound);
  14364. const newValue = capValue(offset / screenRange * range + min, capMin, capMax);
  14365. if (snap && newValue >= min && newValue <= max) {
  14366. return snapValueOf(newValue, min, max, step, snapStart);
  14367. } else if (rounded) {
  14368. return Math.round(newValue);
  14369. } else {
  14370. return newValue;
  14371. }
  14372. }
  14373. };
  14374. const findOffsetOfValue$2 = args => {
  14375. const {min, max, range, value, hasMinEdge, hasMaxEdge, maxBound, maxOffset, centerMinEdge, centerMaxEdge} = args;
  14376. if (value < min) {
  14377. return hasMinEdge ? 0 : centerMinEdge;
  14378. } else if (value > max) {
  14379. return hasMaxEdge ? maxBound : centerMaxEdge;
  14380. } else {
  14381. return (value - min) / range * maxOffset;
  14382. }
  14383. };
  14384. const top = 'top', right = 'right', bottom = 'bottom', left = 'left', width = 'width', height = 'height';
  14385. const getBounds = component => component.element.dom.getBoundingClientRect();
  14386. const getBoundsProperty = (bounds, property) => bounds[property];
  14387. const getMinXBounds = component => {
  14388. const bounds = getBounds(component);
  14389. return getBoundsProperty(bounds, left);
  14390. };
  14391. const getMaxXBounds = component => {
  14392. const bounds = getBounds(component);
  14393. return getBoundsProperty(bounds, right);
  14394. };
  14395. const getMinYBounds = component => {
  14396. const bounds = getBounds(component);
  14397. return getBoundsProperty(bounds, top);
  14398. };
  14399. const getMaxYBounds = component => {
  14400. const bounds = getBounds(component);
  14401. return getBoundsProperty(bounds, bottom);
  14402. };
  14403. const getXScreenRange = component => {
  14404. const bounds = getBounds(component);
  14405. return getBoundsProperty(bounds, width);
  14406. };
  14407. const getYScreenRange = component => {
  14408. const bounds = getBounds(component);
  14409. return getBoundsProperty(bounds, height);
  14410. };
  14411. const getCenterOffsetOf = (componentMinEdge, componentMaxEdge, spectrumMinEdge) => (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge;
  14412. const getXCenterOffSetOf = (component, spectrum) => {
  14413. const componentBounds = getBounds(component);
  14414. const spectrumBounds = getBounds(spectrum);
  14415. const componentMinEdge = getBoundsProperty(componentBounds, left);
  14416. const componentMaxEdge = getBoundsProperty(componentBounds, right);
  14417. const spectrumMinEdge = getBoundsProperty(spectrumBounds, left);
  14418. return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  14419. };
  14420. const getYCenterOffSetOf = (component, spectrum) => {
  14421. const componentBounds = getBounds(component);
  14422. const spectrumBounds = getBounds(spectrum);
  14423. const componentMinEdge = getBoundsProperty(componentBounds, top);
  14424. const componentMaxEdge = getBoundsProperty(componentBounds, bottom);
  14425. const spectrumMinEdge = getBoundsProperty(spectrumBounds, top);
  14426. return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  14427. };
  14428. const fireSliderChange$2 = (spectrum, value) => {
  14429. emitWith(spectrum, sliderChangeEvent(), { value });
  14430. };
  14431. const findValueOfOffset$1 = (spectrum, detail, left) => {
  14432. const args = {
  14433. min: minX(detail),
  14434. max: maxX(detail),
  14435. range: xRange(detail),
  14436. value: left,
  14437. step: step(detail),
  14438. snap: snap(detail),
  14439. snapStart: snapStart(detail),
  14440. rounded: rounded(detail),
  14441. hasMinEdge: hasLEdge(detail),
  14442. hasMaxEdge: hasREdge(detail),
  14443. minBound: getMinXBounds(spectrum),
  14444. maxBound: getMaxXBounds(spectrum),
  14445. screenRange: getXScreenRange(spectrum)
  14446. };
  14447. return findValueOf(args);
  14448. };
  14449. const setValueFrom$2 = (spectrum, detail, value) => {
  14450. const xValue = findValueOfOffset$1(spectrum, detail, value);
  14451. const sliderVal = xValue;
  14452. fireSliderChange$2(spectrum, sliderVal);
  14453. return xValue;
  14454. };
  14455. const setToMin$2 = (spectrum, detail) => {
  14456. const min = minX(detail);
  14457. fireSliderChange$2(spectrum, min);
  14458. };
  14459. const setToMax$2 = (spectrum, detail) => {
  14460. const max = maxX(detail);
  14461. fireSliderChange$2(spectrum, max);
  14462. };
  14463. const moveBy$2 = (direction, spectrum, detail, useMultiplier) => {
  14464. const f = direction > 0 ? increaseBy : reduceBy;
  14465. const xValue = f(currentValue(detail), minX(detail), maxX(detail), step(detail, useMultiplier));
  14466. fireSliderChange$2(spectrum, xValue);
  14467. return Optional.some(xValue);
  14468. };
  14469. const handleMovement$2 = direction => (spectrum, detail, useMultiplier) => moveBy$2(direction, spectrum, detail, useMultiplier).map(always);
  14470. const getValueFromEvent$2 = simulatedEvent => {
  14471. const pos = getEventSource(simulatedEvent);
  14472. return pos.map(p => p.left);
  14473. };
  14474. const findOffsetOfValue$1 = (spectrum, detail, value, minEdge, maxEdge) => {
  14475. const minOffset = 0;
  14476. const maxOffset = getXScreenRange(spectrum);
  14477. const centerMinEdge = minEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(minOffset);
  14478. const centerMaxEdge = maxEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
  14479. const args = {
  14480. min: minX(detail),
  14481. max: maxX(detail),
  14482. range: xRange(detail),
  14483. value,
  14484. hasMinEdge: hasLEdge(detail),
  14485. hasMaxEdge: hasREdge(detail),
  14486. minBound: getMinXBounds(spectrum),
  14487. minOffset,
  14488. maxBound: getMaxXBounds(spectrum),
  14489. maxOffset,
  14490. centerMinEdge,
  14491. centerMaxEdge
  14492. };
  14493. return findOffsetOfValue$2(args);
  14494. };
  14495. const findPositionOfValue$1 = (slider, spectrum, value, minEdge, maxEdge, detail) => {
  14496. const offset = findOffsetOfValue$1(spectrum, detail, value, minEdge, maxEdge);
  14497. return getMinXBounds(spectrum) - getMinXBounds(slider) + offset;
  14498. };
  14499. const setPositionFromValue$2 = (slider, thumb, detail, edges) => {
  14500. const value = currentValue(detail);
  14501. const pos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
  14502. const thumbRadius = get$c(thumb.element) / 2;
  14503. set$8(thumb.element, 'left', pos - thumbRadius + 'px');
  14504. };
  14505. const onLeft$2 = handleMovement$2(-1);
  14506. const onRight$2 = handleMovement$2(1);
  14507. const onUp$2 = Optional.none;
  14508. const onDown$2 = Optional.none;
  14509. const edgeActions$2 = {
  14510. 'top-left': Optional.none(),
  14511. 'top': Optional.none(),
  14512. 'top-right': Optional.none(),
  14513. 'right': Optional.some(setToREdge),
  14514. 'bottom-right': Optional.none(),
  14515. 'bottom': Optional.none(),
  14516. 'bottom-left': Optional.none(),
  14517. 'left': Optional.some(setToLEdge)
  14518. };
  14519. var HorizontalModel = /*#__PURE__*/Object.freeze({
  14520. __proto__: null,
  14521. setValueFrom: setValueFrom$2,
  14522. setToMin: setToMin$2,
  14523. setToMax: setToMax$2,
  14524. findValueOfOffset: findValueOfOffset$1,
  14525. getValueFromEvent: getValueFromEvent$2,
  14526. findPositionOfValue: findPositionOfValue$1,
  14527. setPositionFromValue: setPositionFromValue$2,
  14528. onLeft: onLeft$2,
  14529. onRight: onRight$2,
  14530. onUp: onUp$2,
  14531. onDown: onDown$2,
  14532. edgeActions: edgeActions$2
  14533. });
  14534. const fireSliderChange$1 = (spectrum, value) => {
  14535. emitWith(spectrum, sliderChangeEvent(), { value });
  14536. };
  14537. const findValueOfOffset = (spectrum, detail, top) => {
  14538. const args = {
  14539. min: minY(detail),
  14540. max: maxY(detail),
  14541. range: yRange(detail),
  14542. value: top,
  14543. step: step(detail),
  14544. snap: snap(detail),
  14545. snapStart: snapStart(detail),
  14546. rounded: rounded(detail),
  14547. hasMinEdge: hasTEdge(detail),
  14548. hasMaxEdge: hasBEdge(detail),
  14549. minBound: getMinYBounds(spectrum),
  14550. maxBound: getMaxYBounds(spectrum),
  14551. screenRange: getYScreenRange(spectrum)
  14552. };
  14553. return findValueOf(args);
  14554. };
  14555. const setValueFrom$1 = (spectrum, detail, value) => {
  14556. const yValue = findValueOfOffset(spectrum, detail, value);
  14557. const sliderVal = yValue;
  14558. fireSliderChange$1(spectrum, sliderVal);
  14559. return yValue;
  14560. };
  14561. const setToMin$1 = (spectrum, detail) => {
  14562. const min = minY(detail);
  14563. fireSliderChange$1(spectrum, min);
  14564. };
  14565. const setToMax$1 = (spectrum, detail) => {
  14566. const max = maxY(detail);
  14567. fireSliderChange$1(spectrum, max);
  14568. };
  14569. const moveBy$1 = (direction, spectrum, detail, useMultiplier) => {
  14570. const f = direction > 0 ? increaseBy : reduceBy;
  14571. const yValue = f(currentValue(detail), minY(detail), maxY(detail), step(detail, useMultiplier));
  14572. fireSliderChange$1(spectrum, yValue);
  14573. return Optional.some(yValue);
  14574. };
  14575. const handleMovement$1 = direction => (spectrum, detail, useMultiplier) => moveBy$1(direction, spectrum, detail, useMultiplier).map(always);
  14576. const getValueFromEvent$1 = simulatedEvent => {
  14577. const pos = getEventSource(simulatedEvent);
  14578. return pos.map(p => {
  14579. return p.top;
  14580. });
  14581. };
  14582. const findOffsetOfValue = (spectrum, detail, value, minEdge, maxEdge) => {
  14583. const minOffset = 0;
  14584. const maxOffset = getYScreenRange(spectrum);
  14585. const centerMinEdge = minEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(minOffset);
  14586. const centerMaxEdge = maxEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
  14587. const args = {
  14588. min: minY(detail),
  14589. max: maxY(detail),
  14590. range: yRange(detail),
  14591. value,
  14592. hasMinEdge: hasTEdge(detail),
  14593. hasMaxEdge: hasBEdge(detail),
  14594. minBound: getMinYBounds(spectrum),
  14595. minOffset,
  14596. maxBound: getMaxYBounds(spectrum),
  14597. maxOffset,
  14598. centerMinEdge,
  14599. centerMaxEdge
  14600. };
  14601. return findOffsetOfValue$2(args);
  14602. };
  14603. const findPositionOfValue = (slider, spectrum, value, minEdge, maxEdge, detail) => {
  14604. const offset = findOffsetOfValue(spectrum, detail, value, minEdge, maxEdge);
  14605. return getMinYBounds(spectrum) - getMinYBounds(slider) + offset;
  14606. };
  14607. const setPositionFromValue$1 = (slider, thumb, detail, edges) => {
  14608. const value = currentValue(detail);
  14609. const pos = findPositionOfValue(slider, edges.getSpectrum(slider), value, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
  14610. const thumbRadius = get$d(thumb.element) / 2;
  14611. set$8(thumb.element, 'top', pos - thumbRadius + 'px');
  14612. };
  14613. const onLeft$1 = Optional.none;
  14614. const onRight$1 = Optional.none;
  14615. const onUp$1 = handleMovement$1(-1);
  14616. const onDown$1 = handleMovement$1(1);
  14617. const edgeActions$1 = {
  14618. 'top-left': Optional.none(),
  14619. 'top': Optional.some(setToTEdge),
  14620. 'top-right': Optional.none(),
  14621. 'right': Optional.none(),
  14622. 'bottom-right': Optional.none(),
  14623. 'bottom': Optional.some(setToBEdge),
  14624. 'bottom-left': Optional.none(),
  14625. 'left': Optional.none()
  14626. };
  14627. var VerticalModel = /*#__PURE__*/Object.freeze({
  14628. __proto__: null,
  14629. setValueFrom: setValueFrom$1,
  14630. setToMin: setToMin$1,
  14631. setToMax: setToMax$1,
  14632. findValueOfOffset: findValueOfOffset,
  14633. getValueFromEvent: getValueFromEvent$1,
  14634. findPositionOfValue: findPositionOfValue,
  14635. setPositionFromValue: setPositionFromValue$1,
  14636. onLeft: onLeft$1,
  14637. onRight: onRight$1,
  14638. onUp: onUp$1,
  14639. onDown: onDown$1,
  14640. edgeActions: edgeActions$1
  14641. });
  14642. const fireSliderChange = (spectrum, value) => {
  14643. emitWith(spectrum, sliderChangeEvent(), { value });
  14644. };
  14645. const sliderValue = (x, y) => ({
  14646. x,
  14647. y
  14648. });
  14649. const setValueFrom = (spectrum, detail, value) => {
  14650. const xValue = findValueOfOffset$1(spectrum, detail, value.left);
  14651. const yValue = findValueOfOffset(spectrum, detail, value.top);
  14652. const val = sliderValue(xValue, yValue);
  14653. fireSliderChange(spectrum, val);
  14654. return val;
  14655. };
  14656. const moveBy = (direction, isVerticalMovement, spectrum, detail, useMultiplier) => {
  14657. const f = direction > 0 ? increaseBy : reduceBy;
  14658. const xValue = isVerticalMovement ? currentValue(detail).x : f(currentValue(detail).x, minX(detail), maxX(detail), step(detail, useMultiplier));
  14659. const yValue = !isVerticalMovement ? currentValue(detail).y : f(currentValue(detail).y, minY(detail), maxY(detail), step(detail, useMultiplier));
  14660. fireSliderChange(spectrum, sliderValue(xValue, yValue));
  14661. return Optional.some(xValue);
  14662. };
  14663. const handleMovement = (direction, isVerticalMovement) => (spectrum, detail, useMultiplier) => moveBy(direction, isVerticalMovement, spectrum, detail, useMultiplier).map(always);
  14664. const setToMin = (spectrum, detail) => {
  14665. const mX = minX(detail);
  14666. const mY = minY(detail);
  14667. fireSliderChange(spectrum, sliderValue(mX, mY));
  14668. };
  14669. const setToMax = (spectrum, detail) => {
  14670. const mX = maxX(detail);
  14671. const mY = maxY(detail);
  14672. fireSliderChange(spectrum, sliderValue(mX, mY));
  14673. };
  14674. const getValueFromEvent = simulatedEvent => getEventSource(simulatedEvent);
  14675. const setPositionFromValue = (slider, thumb, detail, edges) => {
  14676. const value = currentValue(detail);
  14677. const xPos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value.x, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
  14678. const yPos = findPositionOfValue(slider, edges.getSpectrum(slider), value.y, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
  14679. const thumbXRadius = get$c(thumb.element) / 2;
  14680. const thumbYRadius = get$d(thumb.element) / 2;
  14681. set$8(thumb.element, 'left', xPos - thumbXRadius + 'px');
  14682. set$8(thumb.element, 'top', yPos - thumbYRadius + 'px');
  14683. };
  14684. const onLeft = handleMovement(-1, false);
  14685. const onRight = handleMovement(1, false);
  14686. const onUp = handleMovement(-1, true);
  14687. const onDown = handleMovement(1, true);
  14688. const edgeActions = {
  14689. 'top-left': Optional.some(setToTLEdgeXY),
  14690. 'top': Optional.some(setToTEdgeXY),
  14691. 'top-right': Optional.some(setToTREdgeXY),
  14692. 'right': Optional.some(setToREdgeXY),
  14693. 'bottom-right': Optional.some(setToBREdgeXY),
  14694. 'bottom': Optional.some(setToBEdgeXY),
  14695. 'bottom-left': Optional.some(setToBLEdgeXY),
  14696. 'left': Optional.some(setToLEdgeXY)
  14697. };
  14698. var TwoDModel = /*#__PURE__*/Object.freeze({
  14699. __proto__: null,
  14700. setValueFrom: setValueFrom,
  14701. setToMin: setToMin,
  14702. setToMax: setToMax,
  14703. getValueFromEvent: getValueFromEvent,
  14704. setPositionFromValue: setPositionFromValue,
  14705. onLeft: onLeft,
  14706. onRight: onRight,
  14707. onUp: onUp,
  14708. onDown: onDown,
  14709. edgeActions: edgeActions
  14710. });
  14711. const SliderSchema = [
  14712. defaulted('stepSize', 1),
  14713. defaulted('speedMultiplier', 10),
  14714. defaulted('onChange', noop),
  14715. defaulted('onChoose', noop),
  14716. defaulted('onInit', noop),
  14717. defaulted('onDragStart', noop),
  14718. defaulted('onDragEnd', noop),
  14719. defaulted('snapToGrid', false),
  14720. defaulted('rounded', true),
  14721. option$3('snapStart'),
  14722. requiredOf('model', choose$1('mode', {
  14723. x: [
  14724. defaulted('minX', 0),
  14725. defaulted('maxX', 100),
  14726. customField('value', spec => Cell(spec.mode.minX)),
  14727. required$1('getInitialValue'),
  14728. output$1('manager', HorizontalModel)
  14729. ],
  14730. y: [
  14731. defaulted('minY', 0),
  14732. defaulted('maxY', 100),
  14733. customField('value', spec => Cell(spec.mode.minY)),
  14734. required$1('getInitialValue'),
  14735. output$1('manager', VerticalModel)
  14736. ],
  14737. xy: [
  14738. defaulted('minX', 0),
  14739. defaulted('maxX', 100),
  14740. defaulted('minY', 0),
  14741. defaulted('maxY', 100),
  14742. customField('value', spec => Cell({
  14743. x: spec.mode.minX,
  14744. y: spec.mode.minY
  14745. })),
  14746. required$1('getInitialValue'),
  14747. output$1('manager', TwoDModel)
  14748. ]
  14749. })),
  14750. field('sliderBehaviours', [
  14751. Keying,
  14752. Representing
  14753. ]),
  14754. customField('mouseIsDown', () => Cell(false))
  14755. ];
  14756. const sketch$2 = (detail, components, _spec, _externals) => {
  14757. const getThumb = component => getPartOrDie(component, detail, 'thumb');
  14758. const getSpectrum = component => getPartOrDie(component, detail, 'spectrum');
  14759. const getLeftEdge = component => getPart(component, detail, 'left-edge');
  14760. const getRightEdge = component => getPart(component, detail, 'right-edge');
  14761. const getTopEdge = component => getPart(component, detail, 'top-edge');
  14762. const getBottomEdge = component => getPart(component, detail, 'bottom-edge');
  14763. const modelDetail = detail.model;
  14764. const model = modelDetail.manager;
  14765. const refresh = (slider, thumb) => {
  14766. model.setPositionFromValue(slider, thumb, detail, {
  14767. getLeftEdge,
  14768. getRightEdge,
  14769. getTopEdge,
  14770. getBottomEdge,
  14771. getSpectrum
  14772. });
  14773. };
  14774. const setValue = (slider, newValue) => {
  14775. modelDetail.value.set(newValue);
  14776. const thumb = getThumb(slider);
  14777. refresh(slider, thumb);
  14778. };
  14779. const changeValue = (slider, newValue) => {
  14780. setValue(slider, newValue);
  14781. const thumb = getThumb(slider);
  14782. detail.onChange(slider, thumb, newValue);
  14783. return Optional.some(true);
  14784. };
  14785. const resetToMin = slider => {
  14786. model.setToMin(slider, detail);
  14787. };
  14788. const resetToMax = slider => {
  14789. model.setToMax(slider, detail);
  14790. };
  14791. const choose = slider => {
  14792. const fireOnChoose = () => {
  14793. getPart(slider, detail, 'thumb').each(thumb => {
  14794. const value = modelDetail.value.get();
  14795. detail.onChoose(slider, thumb, value);
  14796. });
  14797. };
  14798. const wasDown = detail.mouseIsDown.get();
  14799. detail.mouseIsDown.set(false);
  14800. if (wasDown) {
  14801. fireOnChoose();
  14802. }
  14803. };
  14804. const onDragStart = (slider, simulatedEvent) => {
  14805. simulatedEvent.stop();
  14806. detail.mouseIsDown.set(true);
  14807. detail.onDragStart(slider, getThumb(slider));
  14808. };
  14809. const onDragEnd = (slider, simulatedEvent) => {
  14810. simulatedEvent.stop();
  14811. detail.onDragEnd(slider, getThumb(slider));
  14812. choose(slider);
  14813. };
  14814. const focusWidget = component => {
  14815. getPart(component, detail, 'spectrum').map(Keying.focusIn);
  14816. };
  14817. return {
  14818. uid: detail.uid,
  14819. dom: detail.dom,
  14820. components,
  14821. behaviours: augment(detail.sliderBehaviours, [
  14822. Keying.config({
  14823. mode: 'special',
  14824. focusIn: focusWidget
  14825. }),
  14826. Representing.config({
  14827. store: {
  14828. mode: 'manual',
  14829. getValue: _ => {
  14830. return modelDetail.value.get();
  14831. },
  14832. setValue
  14833. }
  14834. }),
  14835. Receiving.config({ channels: { [mouseReleased()]: { onReceive: choose } } })
  14836. ]),
  14837. events: derive$2([
  14838. run$1(sliderChangeEvent(), (slider, simulatedEvent) => {
  14839. changeValue(slider, simulatedEvent.event.value);
  14840. }),
  14841. runOnAttached((slider, _simulatedEvent) => {
  14842. const getInitial = modelDetail.getInitialValue();
  14843. modelDetail.value.set(getInitial);
  14844. const thumb = getThumb(slider);
  14845. refresh(slider, thumb);
  14846. const spectrum = getSpectrum(slider);
  14847. detail.onInit(slider, thumb, spectrum, modelDetail.value.get());
  14848. }),
  14849. run$1(touchstart(), onDragStart),
  14850. run$1(touchend(), onDragEnd),
  14851. run$1(mousedown(), (component, event) => {
  14852. focusWidget(component);
  14853. onDragStart(component, event);
  14854. }),
  14855. run$1(mouseup(), onDragEnd)
  14856. ]),
  14857. apis: {
  14858. resetToMin,
  14859. resetToMax,
  14860. setValue,
  14861. refresh
  14862. },
  14863. domModification: { styles: { position: 'relative' } }
  14864. };
  14865. };
  14866. const Slider = composite({
  14867. name: 'Slider',
  14868. configFields: SliderSchema,
  14869. partFields: SliderParts,
  14870. factory: sketch$2,
  14871. apis: {
  14872. setValue: (apis, slider, value) => {
  14873. apis.setValue(slider, value);
  14874. },
  14875. resetToMin: (apis, slider) => {
  14876. apis.resetToMin(slider);
  14877. },
  14878. resetToMax: (apis, slider) => {
  14879. apis.resetToMax(slider);
  14880. },
  14881. refresh: (apis, slider) => {
  14882. apis.refresh(slider);
  14883. }
  14884. }
  14885. });
  14886. const fieldsUpdate = generate$6('rgb-hex-update');
  14887. const sliderUpdate = generate$6('slider-update');
  14888. const paletteUpdate = generate$6('palette-update');
  14889. const sliderFactory = (translate, getClass) => {
  14890. const spectrum = Slider.parts.spectrum({
  14891. dom: {
  14892. tag: 'div',
  14893. classes: [getClass('hue-slider-spectrum')],
  14894. attributes: { role: 'presentation' }
  14895. }
  14896. });
  14897. const thumb = Slider.parts.thumb({
  14898. dom: {
  14899. tag: 'div',
  14900. classes: [getClass('hue-slider-thumb')],
  14901. attributes: { role: 'presentation' }
  14902. }
  14903. });
  14904. return Slider.sketch({
  14905. dom: {
  14906. tag: 'div',
  14907. classes: [getClass('hue-slider')],
  14908. attributes: {
  14909. 'role': 'slider',
  14910. 'aria-valuemin': 0,
  14911. 'aria-valuemax': 360,
  14912. 'aria-valuenow': 120
  14913. }
  14914. },
  14915. rounded: false,
  14916. model: {
  14917. mode: 'y',
  14918. getInitialValue: constant$1(0)
  14919. },
  14920. components: [
  14921. spectrum,
  14922. thumb
  14923. ],
  14924. sliderBehaviours: derive$1([Focusing.config({})]),
  14925. onChange: (slider, _thumb, value) => {
  14926. set$9(slider.element, 'aria-valuenow', Math.floor(360 - value * 3.6));
  14927. emitWith(slider, sliderUpdate, { value });
  14928. }
  14929. });
  14930. };
  14931. const owner$1 = 'form';
  14932. const schema$i = [field('formBehaviours', [Representing])];
  14933. const getPartName$1 = name => '<alloy.field.' + name + '>';
  14934. const sketch$1 = fSpec => {
  14935. const parts = (() => {
  14936. const record = [];
  14937. const field = (name, config) => {
  14938. record.push(name);
  14939. return generateOne$1(owner$1, getPartName$1(name), config);
  14940. };
  14941. return {
  14942. field,
  14943. record: constant$1(record)
  14944. };
  14945. })();
  14946. const spec = fSpec(parts);
  14947. const partNames = parts.record();
  14948. const fieldParts = map$2(partNames, n => required({
  14949. name: n,
  14950. pname: getPartName$1(n)
  14951. }));
  14952. return composite$1(owner$1, schema$i, fieldParts, make$4, spec);
  14953. };
  14954. const toResult = (o, e) => o.fold(() => Result.error(e), Result.value);
  14955. const make$4 = (detail, components) => ({
  14956. uid: detail.uid,
  14957. dom: detail.dom,
  14958. components,
  14959. behaviours: augment(detail.formBehaviours, [Representing.config({
  14960. store: {
  14961. mode: 'manual',
  14962. getValue: form => {
  14963. const resPs = getAllParts(form, detail);
  14964. return map$1(resPs, (resPThunk, pName) => resPThunk().bind(v => {
  14965. const opt = Composing.getCurrent(v);
  14966. return toResult(opt, new Error(`Cannot find a current component to extract the value from for form part '${ pName }': ` + element(v.element)));
  14967. }).map(Representing.getValue));
  14968. },
  14969. setValue: (form, values) => {
  14970. each(values, (newValue, key) => {
  14971. getPart(form, detail, key).each(wrapper => {
  14972. Composing.getCurrent(wrapper).each(field => {
  14973. Representing.setValue(field, newValue);
  14974. });
  14975. });
  14976. });
  14977. }
  14978. }
  14979. })]),
  14980. apis: {
  14981. getField: (form, key) => {
  14982. return getPart(form, detail, key).bind(Composing.getCurrent);
  14983. }
  14984. }
  14985. });
  14986. const Form = {
  14987. getField: makeApi((apis, component, key) => apis.getField(component, key)),
  14988. sketch: sketch$1
  14989. };
  14990. const validInput = generate$6('valid-input');
  14991. const invalidInput = generate$6('invalid-input');
  14992. const validatingInput = generate$6('validating-input');
  14993. const translatePrefix = 'colorcustom.rgb.';
  14994. const rgbFormFactory = (translate, getClass, onValidHexx, onInvalidHexx) => {
  14995. const invalidation = (label, isValid) => Invalidating.config({
  14996. invalidClass: getClass('invalid'),
  14997. notify: {
  14998. onValidate: comp => {
  14999. emitWith(comp, validatingInput, { type: label });
  15000. },
  15001. onValid: comp => {
  15002. emitWith(comp, validInput, {
  15003. type: label,
  15004. value: Representing.getValue(comp)
  15005. });
  15006. },
  15007. onInvalid: comp => {
  15008. emitWith(comp, invalidInput, {
  15009. type: label,
  15010. value: Representing.getValue(comp)
  15011. });
  15012. }
  15013. },
  15014. validator: {
  15015. validate: comp => {
  15016. const value = Representing.getValue(comp);
  15017. const res = isValid(value) ? Result.value(true) : Result.error(translate('aria.input.invalid'));
  15018. return Future.pure(res);
  15019. },
  15020. validateOnLoad: false
  15021. }
  15022. });
  15023. const renderTextField = (isValid, name, label, description, data) => {
  15024. const helptext = translate(translatePrefix + 'range');
  15025. const pLabel = FormField.parts.label({
  15026. dom: {
  15027. tag: 'label',
  15028. attributes: { 'aria-label': description }
  15029. },
  15030. components: [text$2(label)]
  15031. });
  15032. const pField = FormField.parts.field({
  15033. data,
  15034. factory: Input,
  15035. inputAttributes: {
  15036. type: 'text',
  15037. ...name === 'hex' ? { 'aria-live': 'polite' } : {}
  15038. },
  15039. inputClasses: [getClass('textfield')],
  15040. inputBehaviours: derive$1([
  15041. invalidation(name, isValid),
  15042. Tabstopping.config({})
  15043. ]),
  15044. onSetValue: input => {
  15045. if (Invalidating.isInvalid(input)) {
  15046. const run = Invalidating.run(input);
  15047. run.get(noop);
  15048. }
  15049. }
  15050. });
  15051. const comps = [
  15052. pLabel,
  15053. pField
  15054. ];
  15055. const concats = name !== 'hex' ? [FormField.parts['aria-descriptor']({ text: helptext })] : [];
  15056. const components = comps.concat(concats);
  15057. return {
  15058. dom: {
  15059. tag: 'div',
  15060. attributes: { role: 'presentation' }
  15061. },
  15062. components
  15063. };
  15064. };
  15065. const copyRgbToHex = (form, rgba) => {
  15066. const hex = fromRgba(rgba);
  15067. Form.getField(form, 'hex').each(hexField => {
  15068. if (!Focusing.isFocused(hexField)) {
  15069. Representing.setValue(form, { hex: hex.value });
  15070. }
  15071. });
  15072. return hex;
  15073. };
  15074. const copyRgbToForm = (form, rgb) => {
  15075. const red = rgb.red;
  15076. const green = rgb.green;
  15077. const blue = rgb.blue;
  15078. Representing.setValue(form, {
  15079. red,
  15080. green,
  15081. blue
  15082. });
  15083. };
  15084. const memPreview = record({
  15085. dom: {
  15086. tag: 'div',
  15087. classes: [getClass('rgba-preview')],
  15088. styles: { 'background-color': 'white' },
  15089. attributes: { role: 'presentation' }
  15090. }
  15091. });
  15092. const updatePreview = (anyInSystem, hex) => {
  15093. memPreview.getOpt(anyInSystem).each(preview => {
  15094. set$8(preview.element, 'background-color', '#' + hex.value);
  15095. });
  15096. };
  15097. const factory = () => {
  15098. const state = {
  15099. red: Cell(Optional.some(255)),
  15100. green: Cell(Optional.some(255)),
  15101. blue: Cell(Optional.some(255)),
  15102. hex: Cell(Optional.some('ffffff'))
  15103. };
  15104. const copyHexToRgb = (form, hex) => {
  15105. const rgb = fromHex(hex);
  15106. copyRgbToForm(form, rgb);
  15107. setValueRgb(rgb);
  15108. };
  15109. const get = prop => state[prop].get();
  15110. const set = (prop, value) => {
  15111. state[prop].set(value);
  15112. };
  15113. const getValueRgb = () => get('red').bind(red => get('green').bind(green => get('blue').map(blue => rgbaColour(red, green, blue, 1))));
  15114. const setValueRgb = rgb => {
  15115. const red = rgb.red;
  15116. const green = rgb.green;
  15117. const blue = rgb.blue;
  15118. set('red', Optional.some(red));
  15119. set('green', Optional.some(green));
  15120. set('blue', Optional.some(blue));
  15121. };
  15122. const onInvalidInput = (form, simulatedEvent) => {
  15123. const data = simulatedEvent.event;
  15124. if (data.type !== 'hex') {
  15125. set(data.type, Optional.none());
  15126. } else {
  15127. onInvalidHexx(form);
  15128. }
  15129. };
  15130. const onValidHex = (form, value) => {
  15131. onValidHexx(form);
  15132. const hex = hexColour(value);
  15133. set('hex', Optional.some(hex.value));
  15134. const rgb = fromHex(hex);
  15135. copyRgbToForm(form, rgb);
  15136. setValueRgb(rgb);
  15137. emitWith(form, fieldsUpdate, { hex });
  15138. updatePreview(form, hex);
  15139. };
  15140. const onValidRgb = (form, prop, value) => {
  15141. const val = parseInt(value, 10);
  15142. set(prop, Optional.some(val));
  15143. getValueRgb().each(rgb => {
  15144. const hex = copyRgbToHex(form, rgb);
  15145. emitWith(form, fieldsUpdate, { hex });
  15146. updatePreview(form, hex);
  15147. });
  15148. };
  15149. const isHexInputEvent = data => data.type === 'hex';
  15150. const onValidInput = (form, simulatedEvent) => {
  15151. const data = simulatedEvent.event;
  15152. if (isHexInputEvent(data)) {
  15153. onValidHex(form, data.value);
  15154. } else {
  15155. onValidRgb(form, data.type, data.value);
  15156. }
  15157. };
  15158. const formPartStrings = key => ({
  15159. label: translate(translatePrefix + key + '.label'),
  15160. description: translate(translatePrefix + key + '.description')
  15161. });
  15162. const redStrings = formPartStrings('red');
  15163. const greenStrings = formPartStrings('green');
  15164. const blueStrings = formPartStrings('blue');
  15165. const hexStrings = formPartStrings('hex');
  15166. return deepMerge(Form.sketch(parts => ({
  15167. dom: {
  15168. tag: 'form',
  15169. classes: [getClass('rgb-form')],
  15170. attributes: { 'aria-label': translate('aria.color.picker') }
  15171. },
  15172. components: [
  15173. parts.field('red', FormField.sketch(renderTextField(isRgbaComponent, 'red', redStrings.label, redStrings.description, 255))),
  15174. parts.field('green', FormField.sketch(renderTextField(isRgbaComponent, 'green', greenStrings.label, greenStrings.description, 255))),
  15175. parts.field('blue', FormField.sketch(renderTextField(isRgbaComponent, 'blue', blueStrings.label, blueStrings.description, 255))),
  15176. parts.field('hex', FormField.sketch(renderTextField(isHexString, 'hex', hexStrings.label, hexStrings.description, 'ffffff'))),
  15177. memPreview.asSpec()
  15178. ],
  15179. formBehaviours: derive$1([
  15180. Invalidating.config({ invalidClass: getClass('form-invalid') }),
  15181. config('rgb-form-events', [
  15182. run$1(validInput, onValidInput),
  15183. run$1(invalidInput, onInvalidInput),
  15184. run$1(validatingInput, onInvalidInput)
  15185. ])
  15186. ])
  15187. })), {
  15188. apis: {
  15189. updateHex: (form, hex) => {
  15190. Representing.setValue(form, { hex: hex.value });
  15191. copyHexToRgb(form, hex);
  15192. updatePreview(form, hex);
  15193. }
  15194. }
  15195. });
  15196. };
  15197. const rgbFormSketcher = single({
  15198. factory,
  15199. name: 'RgbForm',
  15200. configFields: [],
  15201. apis: {
  15202. updateHex: (apis, form, hex) => {
  15203. apis.updateHex(form, hex);
  15204. }
  15205. },
  15206. extraApis: {}
  15207. });
  15208. return rgbFormSketcher;
  15209. };
  15210. const paletteFactory = (translate, getClass) => {
  15211. const spectrumPart = Slider.parts.spectrum({
  15212. dom: {
  15213. tag: 'canvas',
  15214. attributes: { role: 'presentation' },
  15215. classes: [getClass('sv-palette-spectrum')]
  15216. }
  15217. });
  15218. const thumbPart = Slider.parts.thumb({
  15219. dom: {
  15220. tag: 'div',
  15221. attributes: { role: 'presentation' },
  15222. classes: [getClass('sv-palette-thumb')],
  15223. innerHtml: `<div class=${ getClass('sv-palette-inner-thumb') } role="presentation"></div>`
  15224. }
  15225. });
  15226. const setColour = (canvas, rgba) => {
  15227. const {width, height} = canvas;
  15228. const ctx = canvas.getContext('2d');
  15229. if (ctx === null) {
  15230. return;
  15231. }
  15232. ctx.fillStyle = rgba;
  15233. ctx.fillRect(0, 0, width, height);
  15234. const grdWhite = ctx.createLinearGradient(0, 0, width, 0);
  15235. grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
  15236. grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
  15237. ctx.fillStyle = grdWhite;
  15238. ctx.fillRect(0, 0, width, height);
  15239. const grdBlack = ctx.createLinearGradient(0, 0, 0, height);
  15240. grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
  15241. grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
  15242. ctx.fillStyle = grdBlack;
  15243. ctx.fillRect(0, 0, width, height);
  15244. };
  15245. const setPaletteHue = (slider, hue) => {
  15246. const canvas = slider.components()[0].element.dom;
  15247. const hsv = hsvColour(hue, 100, 100);
  15248. const rgba = fromHsv(hsv);
  15249. setColour(canvas, toString(rgba));
  15250. };
  15251. const setPaletteThumb = (slider, hex) => {
  15252. const hsv = fromRgb(fromHex(hex));
  15253. Slider.setValue(slider, {
  15254. x: hsv.saturation,
  15255. y: 100 - hsv.value
  15256. });
  15257. set$9(slider.element, 'aria-valuetext', translate([
  15258. 'Saturation {0}%, Brightness {1}%',
  15259. hsv.saturation,
  15260. hsv.value
  15261. ]));
  15262. };
  15263. const factory = _detail => {
  15264. const getInitialValue = constant$1({
  15265. x: 0,
  15266. y: 0
  15267. });
  15268. const onChange = (slider, _thumb, value) => {
  15269. if (!isNumber(value)) {
  15270. set$9(slider.element, 'aria-valuetext', translate([
  15271. 'Saturation {0}%, Brightness {1}%',
  15272. Math.floor(value.x),
  15273. Math.floor(100 - value.y)
  15274. ]));
  15275. }
  15276. emitWith(slider, paletteUpdate, { value });
  15277. };
  15278. const onInit = (_slider, _thumb, spectrum, _value) => {
  15279. setColour(spectrum.element.dom, toString(red));
  15280. };
  15281. const sliderBehaviours = derive$1([
  15282. Composing.config({ find: Optional.some }),
  15283. Focusing.config({})
  15284. ]);
  15285. return Slider.sketch({
  15286. dom: {
  15287. tag: 'div',
  15288. attributes: {
  15289. 'role': 'slider',
  15290. 'aria-valuetext': translate([
  15291. 'Saturation {0}%, Brightness {1}%',
  15292. 0,
  15293. 0
  15294. ])
  15295. },
  15296. classes: [getClass('sv-palette')]
  15297. },
  15298. model: {
  15299. mode: 'xy',
  15300. getInitialValue
  15301. },
  15302. rounded: false,
  15303. components: [
  15304. spectrumPart,
  15305. thumbPart
  15306. ],
  15307. onChange,
  15308. onInit,
  15309. sliderBehaviours
  15310. });
  15311. };
  15312. const saturationBrightnessPaletteSketcher = single({
  15313. factory,
  15314. name: 'SaturationBrightnessPalette',
  15315. configFields: [],
  15316. apis: {
  15317. setHue: (_apis, slider, hue) => {
  15318. setPaletteHue(slider, hue);
  15319. },
  15320. setThumb: (_apis, slider, hex) => {
  15321. setPaletteThumb(slider, hex);
  15322. }
  15323. },
  15324. extraApis: {}
  15325. });
  15326. return saturationBrightnessPaletteSketcher;
  15327. };
  15328. const makeFactory = (translate, getClass) => {
  15329. const factory = detail => {
  15330. const rgbForm = rgbFormFactory(translate, getClass, detail.onValidHex, detail.onInvalidHex);
  15331. const sbPalette = paletteFactory(translate, getClass);
  15332. const hueSliderToDegrees = hue => (100 - hue) / 100 * 360;
  15333. const hueDegreesToSlider = hue => 100 - hue / 360 * 100;
  15334. const state = {
  15335. paletteRgba: Cell(red),
  15336. paletteHue: Cell(0)
  15337. };
  15338. const memSlider = record(sliderFactory(translate, getClass));
  15339. const memPalette = record(sbPalette.sketch({}));
  15340. const memRgb = record(rgbForm.sketch({}));
  15341. const updatePalette = (anyInSystem, _hex, hue) => {
  15342. memPalette.getOpt(anyInSystem).each(palette => {
  15343. sbPalette.setHue(palette, hue);
  15344. });
  15345. };
  15346. const updateFields = (anyInSystem, hex) => {
  15347. memRgb.getOpt(anyInSystem).each(form => {
  15348. rgbForm.updateHex(form, hex);
  15349. });
  15350. };
  15351. const updateSlider = (anyInSystem, _hex, hue) => {
  15352. memSlider.getOpt(anyInSystem).each(slider => {
  15353. Slider.setValue(slider, hueDegreesToSlider(hue));
  15354. });
  15355. };
  15356. const updatePaletteThumb = (anyInSystem, hex) => {
  15357. memPalette.getOpt(anyInSystem).each(palette => {
  15358. sbPalette.setThumb(palette, hex);
  15359. });
  15360. };
  15361. const updateState = (hex, hue) => {
  15362. const rgba = fromHex(hex);
  15363. state.paletteRgba.set(rgba);
  15364. state.paletteHue.set(hue);
  15365. };
  15366. const runUpdates = (anyInSystem, hex, hue, updates) => {
  15367. updateState(hex, hue);
  15368. each$1(updates, update => {
  15369. update(anyInSystem, hex, hue);
  15370. });
  15371. };
  15372. const onPaletteUpdate = () => {
  15373. const updates = [updateFields];
  15374. return (form, simulatedEvent) => {
  15375. const value = simulatedEvent.event.value;
  15376. const oldHue = state.paletteHue.get();
  15377. const newHsv = hsvColour(oldHue, value.x, 100 - value.y);
  15378. const newHex = hsvToHex(newHsv);
  15379. runUpdates(form, newHex, oldHue, updates);
  15380. };
  15381. };
  15382. const onSliderUpdate = () => {
  15383. const updates = [
  15384. updatePalette,
  15385. updateFields
  15386. ];
  15387. return (form, simulatedEvent) => {
  15388. const hue = hueSliderToDegrees(simulatedEvent.event.value);
  15389. const oldRgb = state.paletteRgba.get();
  15390. const oldHsv = fromRgb(oldRgb);
  15391. const newHsv = hsvColour(hue, oldHsv.saturation, oldHsv.value);
  15392. const newHex = hsvToHex(newHsv);
  15393. runUpdates(form, newHex, hue, updates);
  15394. };
  15395. };
  15396. const onFieldsUpdate = () => {
  15397. const updates = [
  15398. updatePalette,
  15399. updateSlider,
  15400. updatePaletteThumb
  15401. ];
  15402. return (form, simulatedEvent) => {
  15403. const hex = simulatedEvent.event.hex;
  15404. const hsv = hexToHsv(hex);
  15405. runUpdates(form, hex, hsv.hue, updates);
  15406. };
  15407. };
  15408. return {
  15409. uid: detail.uid,
  15410. dom: detail.dom,
  15411. components: [
  15412. memPalette.asSpec(),
  15413. memSlider.asSpec(),
  15414. memRgb.asSpec()
  15415. ],
  15416. behaviours: derive$1([
  15417. config('colour-picker-events', [
  15418. run$1(fieldsUpdate, onFieldsUpdate()),
  15419. run$1(paletteUpdate, onPaletteUpdate()),
  15420. run$1(sliderUpdate, onSliderUpdate())
  15421. ]),
  15422. Composing.config({ find: comp => memRgb.getOpt(comp) }),
  15423. Keying.config({ mode: 'acyclic' })
  15424. ])
  15425. };
  15426. };
  15427. const colourPickerSketcher = single({
  15428. name: 'ColourPicker',
  15429. configFields: [
  15430. required$1('dom'),
  15431. defaulted('onValidHex', noop),
  15432. defaulted('onInvalidHex', noop)
  15433. ],
  15434. factory
  15435. });
  15436. return colourPickerSketcher;
  15437. };
  15438. const self = () => Composing.config({ find: Optional.some });
  15439. const memento$1 = mem => Composing.config({ find: mem.getOpt });
  15440. const childAt = index => Composing.config({ find: comp => child$2(comp.element, index).bind(element => comp.getSystem().getByDom(element).toOptional()) });
  15441. const ComposingConfigs = {
  15442. self,
  15443. memento: memento$1,
  15444. childAt
  15445. };
  15446. const processors = objOf([
  15447. defaulted('preprocess', identity),
  15448. defaulted('postprocess', identity)
  15449. ]);
  15450. const memento = (mem, rawProcessors) => {
  15451. const ps = asRawOrDie$1('RepresentingConfigs.memento processors', processors, rawProcessors);
  15452. return Representing.config({
  15453. store: {
  15454. mode: 'manual',
  15455. getValue: comp => {
  15456. const other = mem.get(comp);
  15457. const rawValue = Representing.getValue(other);
  15458. return ps.postprocess(rawValue);
  15459. },
  15460. setValue: (comp, rawValue) => {
  15461. const newValue = ps.preprocess(rawValue);
  15462. const other = mem.get(comp);
  15463. Representing.setValue(other, newValue);
  15464. }
  15465. }
  15466. });
  15467. };
  15468. const withComp = (optInitialValue, getter, setter) => Representing.config({
  15469. store: {
  15470. mode: 'manual',
  15471. ...optInitialValue.map(initialValue => ({ initialValue })).getOr({}),
  15472. getValue: getter,
  15473. setValue: setter
  15474. }
  15475. });
  15476. const withElement = (initialValue, getter, setter) => withComp(initialValue, c => getter(c.element), (c, v) => setter(c.element, v));
  15477. const domHtml = optInitialValue => withElement(optInitialValue, get$9, set$6);
  15478. const memory = initialValue => Representing.config({
  15479. store: {
  15480. mode: 'memory',
  15481. initialValue
  15482. }
  15483. });
  15484. const english = {
  15485. 'colorcustom.rgb.red.label': 'R',
  15486. 'colorcustom.rgb.red.description': 'Red component',
  15487. 'colorcustom.rgb.green.label': 'G',
  15488. 'colorcustom.rgb.green.description': 'Green component',
  15489. 'colorcustom.rgb.blue.label': 'B',
  15490. 'colorcustom.rgb.blue.description': 'Blue component',
  15491. 'colorcustom.rgb.hex.label': '#',
  15492. 'colorcustom.rgb.hex.description': 'Hex color code',
  15493. 'colorcustom.rgb.range': 'Range 0 to 255',
  15494. 'aria.color.picker': 'Color Picker',
  15495. 'aria.input.invalid': 'Invalid input'
  15496. };
  15497. const translate$1 = providerBackstage => key => {
  15498. if (isString(key)) {
  15499. return providerBackstage.translate(english[key]);
  15500. } else {
  15501. return providerBackstage.translate(key);
  15502. }
  15503. };
  15504. const renderColorPicker = (_spec, providerBackstage, initialData) => {
  15505. const getClass = key => 'tox-' + key;
  15506. const colourPickerFactory = makeFactory(translate$1(providerBackstage), getClass);
  15507. const onValidHex = form => {
  15508. emitWith(form, formActionEvent, {
  15509. name: 'hex-valid',
  15510. value: true
  15511. });
  15512. };
  15513. const onInvalidHex = form => {
  15514. emitWith(form, formActionEvent, {
  15515. name: 'hex-valid',
  15516. value: false
  15517. });
  15518. };
  15519. const memPicker = record(colourPickerFactory.sketch({
  15520. dom: {
  15521. tag: 'div',
  15522. classes: [getClass('color-picker-container')],
  15523. attributes: { role: 'presentation' }
  15524. },
  15525. onValidHex,
  15526. onInvalidHex
  15527. }));
  15528. return {
  15529. dom: { tag: 'div' },
  15530. components: [memPicker.asSpec()],
  15531. behaviours: derive$1([
  15532. withComp(initialData, comp => {
  15533. const picker = memPicker.get(comp);
  15534. const optRgbForm = Composing.getCurrent(picker);
  15535. const optHex = optRgbForm.bind(rgbForm => {
  15536. const formValues = Representing.getValue(rgbForm);
  15537. return formValues.hex;
  15538. });
  15539. return optHex.map(hex => '#' + removeLeading(hex, '#')).getOr('');
  15540. }, (comp, newValue) => {
  15541. const pattern = /^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/;
  15542. const valOpt = Optional.from(pattern.exec(newValue)).bind(matches => get$h(matches, 1));
  15543. const picker = memPicker.get(comp);
  15544. const optRgbForm = Composing.getCurrent(picker);
  15545. optRgbForm.fold(() => {
  15546. console.log('Can not find form');
  15547. }, rgbForm => {
  15548. Representing.setValue(rgbForm, { hex: valOpt.getOr('') });
  15549. Form.getField(rgbForm, 'hex').each(hexField => {
  15550. emit(hexField, input());
  15551. });
  15552. });
  15553. }),
  15554. ComposingConfigs.self()
  15555. ])
  15556. };
  15557. };
  15558. var global$2 = tinymce.util.Tools.resolve('tinymce.Resource');
  15559. const isOldCustomEditor = spec => has$2(spec, 'init');
  15560. const renderCustomEditor = spec => {
  15561. const editorApi = value$2();
  15562. const memReplaced = record({ dom: { tag: spec.tag } });
  15563. const initialValue = value$2();
  15564. return {
  15565. dom: {
  15566. tag: 'div',
  15567. classes: ['tox-custom-editor']
  15568. },
  15569. behaviours: derive$1([
  15570. config('custom-editor-events', [runOnAttached(component => {
  15571. memReplaced.getOpt(component).each(ta => {
  15572. (isOldCustomEditor(spec) ? spec.init(ta.element.dom) : global$2.load(spec.scriptId, spec.scriptUrl).then(init => init(ta.element.dom, spec.settings))).then(ea => {
  15573. initialValue.on(cvalue => {
  15574. ea.setValue(cvalue);
  15575. });
  15576. initialValue.clear();
  15577. editorApi.set(ea);
  15578. });
  15579. });
  15580. })]),
  15581. withComp(Optional.none(), () => editorApi.get().fold(() => initialValue.get().getOr(''), ed => ed.getValue()), (component, value) => {
  15582. editorApi.get().fold(() => initialValue.set(value), ed => ed.setValue(value));
  15583. }),
  15584. ComposingConfigs.self()
  15585. ]),
  15586. components: [memReplaced.asSpec()]
  15587. };
  15588. };
  15589. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  15590. const filterByExtension = (files, providersBackstage) => {
  15591. const allowedImageFileTypes = global$1.explode(providersBackstage.getOption('images_file_types'));
  15592. const isFileInAllowedTypes = file => exists(allowedImageFileTypes, type => endsWith(file.name.toLowerCase(), `.${ type.toLowerCase() }`));
  15593. return filter$2(from(files), isFileInAllowedTypes);
  15594. };
  15595. const renderDropZone = (spec, providersBackstage, initialData) => {
  15596. const stopper = (_, se) => {
  15597. se.stop();
  15598. };
  15599. const sequence = actions => (comp, se) => {
  15600. each$1(actions, a => {
  15601. a(comp, se);
  15602. });
  15603. };
  15604. const onDrop = (comp, se) => {
  15605. var _a;
  15606. if (!Disabling.isDisabled(comp)) {
  15607. const transferEvent = se.event.raw;
  15608. handleFiles(comp, (_a = transferEvent.dataTransfer) === null || _a === void 0 ? void 0 : _a.files);
  15609. }
  15610. };
  15611. const onSelect = (component, simulatedEvent) => {
  15612. const input = simulatedEvent.event.raw.target;
  15613. handleFiles(component, input.files);
  15614. };
  15615. const handleFiles = (component, files) => {
  15616. if (files) {
  15617. Representing.setValue(component, filterByExtension(files, providersBackstage));
  15618. emitWith(component, formChangeEvent, { name: spec.name });
  15619. }
  15620. };
  15621. const memInput = record({
  15622. dom: {
  15623. tag: 'input',
  15624. attributes: {
  15625. type: 'file',
  15626. accept: 'image/*'
  15627. },
  15628. styles: { display: 'none' }
  15629. },
  15630. behaviours: derive$1([config('input-file-events', [
  15631. cutter(click()),
  15632. cutter(tap())
  15633. ])])
  15634. });
  15635. const renderField = s => ({
  15636. uid: s.uid,
  15637. dom: {
  15638. tag: 'div',
  15639. classes: ['tox-dropzone-container']
  15640. },
  15641. behaviours: derive$1([
  15642. memory(initialData.getOr([])),
  15643. ComposingConfigs.self(),
  15644. Disabling.config({}),
  15645. Toggling.config({
  15646. toggleClass: 'dragenter',
  15647. toggleOnExecute: false
  15648. }),
  15649. config('dropzone-events', [
  15650. run$1('dragenter', sequence([
  15651. stopper,
  15652. Toggling.toggle
  15653. ])),
  15654. run$1('dragleave', sequence([
  15655. stopper,
  15656. Toggling.toggle
  15657. ])),
  15658. run$1('dragover', stopper),
  15659. run$1('drop', sequence([
  15660. stopper,
  15661. onDrop
  15662. ])),
  15663. run$1(change(), onSelect)
  15664. ])
  15665. ]),
  15666. components: [{
  15667. dom: {
  15668. tag: 'div',
  15669. classes: ['tox-dropzone'],
  15670. styles: {}
  15671. },
  15672. components: [
  15673. {
  15674. dom: { tag: 'p' },
  15675. components: [text$2(providersBackstage.translate('Drop an image here'))]
  15676. },
  15677. Button.sketch({
  15678. dom: {
  15679. tag: 'button',
  15680. styles: { position: 'relative' },
  15681. classes: [
  15682. 'tox-button',
  15683. 'tox-button--secondary'
  15684. ]
  15685. },
  15686. components: [
  15687. text$2(providersBackstage.translate('Browse for an image')),
  15688. memInput.asSpec()
  15689. ],
  15690. action: comp => {
  15691. const inputComp = memInput.get(comp);
  15692. inputComp.element.dom.click();
  15693. },
  15694. buttonBehaviours: derive$1([
  15695. Tabstopping.config({}),
  15696. DisablingConfigs.button(providersBackstage.isDisabled),
  15697. receivingConfig()
  15698. ])
  15699. })
  15700. ]
  15701. }]
  15702. });
  15703. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  15704. const pField = FormField.parts.field({ factory: { sketch: renderField } });
  15705. return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
  15706. };
  15707. const renderGrid = (spec, backstage) => ({
  15708. dom: {
  15709. tag: 'div',
  15710. classes: [
  15711. 'tox-form__grid',
  15712. `tox-form__grid--${ spec.columns }col`
  15713. ]
  15714. },
  15715. components: map$2(spec.items, backstage.interpreter)
  15716. });
  15717. const adaptable = (fn, rate) => {
  15718. let timer = null;
  15719. let args = null;
  15720. const cancel = () => {
  15721. if (!isNull(timer)) {
  15722. clearTimeout(timer);
  15723. timer = null;
  15724. args = null;
  15725. }
  15726. };
  15727. const throttle = (...newArgs) => {
  15728. args = newArgs;
  15729. if (isNull(timer)) {
  15730. timer = setTimeout(() => {
  15731. const tempArgs = args;
  15732. timer = null;
  15733. args = null;
  15734. fn.apply(null, tempArgs);
  15735. }, rate);
  15736. }
  15737. };
  15738. return {
  15739. cancel,
  15740. throttle
  15741. };
  15742. };
  15743. const first = (fn, rate) => {
  15744. let timer = null;
  15745. const cancel = () => {
  15746. if (!isNull(timer)) {
  15747. clearTimeout(timer);
  15748. timer = null;
  15749. }
  15750. };
  15751. const throttle = (...args) => {
  15752. if (isNull(timer)) {
  15753. timer = setTimeout(() => {
  15754. timer = null;
  15755. fn.apply(null, args);
  15756. }, rate);
  15757. }
  15758. };
  15759. return {
  15760. cancel,
  15761. throttle
  15762. };
  15763. };
  15764. const last = (fn, rate) => {
  15765. let timer = null;
  15766. const cancel = () => {
  15767. if (!isNull(timer)) {
  15768. clearTimeout(timer);
  15769. timer = null;
  15770. }
  15771. };
  15772. const throttle = (...args) => {
  15773. cancel();
  15774. timer = setTimeout(() => {
  15775. timer = null;
  15776. fn.apply(null, args);
  15777. }, rate);
  15778. };
  15779. return {
  15780. cancel,
  15781. throttle
  15782. };
  15783. };
  15784. const beforeObject = generate$6('alloy-fake-before-tabstop');
  15785. const afterObject = generate$6('alloy-fake-after-tabstop');
  15786. const craftWithClasses = classes => {
  15787. return {
  15788. dom: {
  15789. tag: 'div',
  15790. styles: {
  15791. width: '1px',
  15792. height: '1px',
  15793. outline: 'none'
  15794. },
  15795. attributes: { tabindex: '0' },
  15796. classes
  15797. },
  15798. behaviours: derive$1([
  15799. Focusing.config({ ignore: true }),
  15800. Tabstopping.config({})
  15801. ])
  15802. };
  15803. };
  15804. const craft = (containerClasses, spec) => {
  15805. return {
  15806. dom: {
  15807. tag: 'div',
  15808. classes: [
  15809. 'tox-navobj',
  15810. ...containerClasses.getOr([])
  15811. ]
  15812. },
  15813. components: [
  15814. craftWithClasses([beforeObject]),
  15815. spec,
  15816. craftWithClasses([afterObject])
  15817. ],
  15818. behaviours: derive$1([ComposingConfigs.childAt(1)])
  15819. };
  15820. };
  15821. const triggerTab = (placeholder, shiftKey) => {
  15822. emitWith(placeholder, keydown(), {
  15823. raw: {
  15824. which: 9,
  15825. shiftKey
  15826. }
  15827. });
  15828. };
  15829. const onFocus = (container, targetComp) => {
  15830. const target = targetComp.element;
  15831. if (has(target, beforeObject)) {
  15832. triggerTab(container, true);
  15833. } else if (has(target, afterObject)) {
  15834. triggerTab(container, false);
  15835. }
  15836. };
  15837. const isPseudoStop = element => {
  15838. return closest(element, [
  15839. '.' + beforeObject,
  15840. '.' + afterObject
  15841. ].join(','), never);
  15842. };
  15843. const dialogChannel = generate$6('update-dialog');
  15844. const titleChannel = generate$6('update-title');
  15845. const bodyChannel = generate$6('update-body');
  15846. const footerChannel = generate$6('update-footer');
  15847. const bodySendMessageChannel = generate$6('body-send-message');
  15848. const dialogFocusShiftedChannel = generate$6('dialog-focus-shifted');
  15849. const browser = detect$2().browser;
  15850. const isSafari = browser.isSafari();
  15851. const isFirefox = browser.isFirefox();
  15852. const isSafariOrFirefox = isSafari || isFirefox;
  15853. const isChromium = browser.isChromium();
  15854. const isElementScrollAtBottom = ({scrollTop, scrollHeight, clientHeight}) => Math.ceil(scrollTop) + clientHeight >= scrollHeight;
  15855. const scrollToY = (win, y) => win.scrollTo(0, y === 'bottom' ? 99999999 : y);
  15856. const getScrollingElement = (doc, html) => {
  15857. const body = doc.body;
  15858. return Optional.from(!/^<!DOCTYPE (html|HTML)/.test(html) && (!isChromium && !isSafari || isNonNullable(body) && (body.scrollTop !== 0 || Math.abs(body.scrollHeight - body.clientHeight) > 1)) ? body : doc.documentElement);
  15859. };
  15860. const writeValue = (iframeElement, html, fallbackFn) => {
  15861. const iframe = iframeElement.dom;
  15862. Optional.from(iframe.contentDocument).fold(fallbackFn, doc => {
  15863. let lastScrollTop = 0;
  15864. const isScrollAtBottom = getScrollingElement(doc, html).map(el => {
  15865. lastScrollTop = el.scrollTop;
  15866. return el;
  15867. }).forall(isElementScrollAtBottom);
  15868. const scrollAfterWrite = () => {
  15869. const win = iframe.contentWindow;
  15870. if (isNonNullable(win)) {
  15871. if (isScrollAtBottom) {
  15872. scrollToY(win, 'bottom');
  15873. } else if (!isScrollAtBottom && isSafariOrFirefox && lastScrollTop !== 0) {
  15874. scrollToY(win, lastScrollTop);
  15875. }
  15876. }
  15877. };
  15878. if (isSafari) {
  15879. iframe.addEventListener('load', scrollAfterWrite, { once: true });
  15880. }
  15881. doc.open();
  15882. doc.write(html);
  15883. doc.close();
  15884. if (!isSafari) {
  15885. scrollAfterWrite();
  15886. }
  15887. });
  15888. };
  15889. const throttleInterval = someIf(isSafariOrFirefox, isSafari ? 500 : 200);
  15890. const writeValueThrottler = throttleInterval.map(interval => adaptable(writeValue, interval));
  15891. const getDynamicSource = (initialData, stream) => {
  15892. const cachedValue = Cell(initialData.getOr(''));
  15893. return {
  15894. getValue: _frameComponent => cachedValue.get(),
  15895. setValue: (frameComponent, html) => {
  15896. if (cachedValue.get() !== html) {
  15897. const iframeElement = frameComponent.element;
  15898. const setSrcdocValue = () => set$9(iframeElement, 'srcdoc', html);
  15899. if (stream) {
  15900. writeValueThrottler.fold(constant$1(writeValue), throttler => throttler.throttle)(iframeElement, html, setSrcdocValue);
  15901. } else {
  15902. setSrcdocValue();
  15903. }
  15904. }
  15905. cachedValue.set(html);
  15906. }
  15907. };
  15908. };
  15909. const renderIFrame = (spec, providersBackstage, initialData) => {
  15910. const baseClass = 'tox-dialog__iframe';
  15911. const opaqueClass = spec.transparent ? [] : [`${ baseClass }--opaque`];
  15912. const containerBorderedClass = spec.border ? [`tox-navobj-bordered`] : [];
  15913. const attributes = {
  15914. ...spec.label.map(title => ({ title })).getOr({}),
  15915. ...initialData.map(html => ({ srcdoc: html })).getOr({}),
  15916. ...spec.sandboxed ? { sandbox: 'allow-scripts allow-same-origin' } : {}
  15917. };
  15918. const sourcing = getDynamicSource(initialData, spec.streamContent);
  15919. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  15920. const factory = newSpec => craft(Optional.from(containerBorderedClass), {
  15921. uid: newSpec.uid,
  15922. dom: {
  15923. tag: 'iframe',
  15924. attributes,
  15925. classes: [
  15926. baseClass,
  15927. ...opaqueClass
  15928. ]
  15929. },
  15930. behaviours: derive$1([
  15931. Tabstopping.config({}),
  15932. Focusing.config({}),
  15933. withComp(initialData, sourcing.getValue, sourcing.setValue),
  15934. Receiving.config({
  15935. channels: {
  15936. [dialogFocusShiftedChannel]: {
  15937. onReceive: (comp, message) => {
  15938. message.newFocus.each(newFocus => {
  15939. parentElement(comp.element).each(parent => {
  15940. const f = eq(comp.element, newFocus) ? add$2 : remove$2;
  15941. f(parent, 'tox-navobj-bordered-focus');
  15942. });
  15943. });
  15944. }
  15945. }
  15946. }
  15947. })
  15948. ])
  15949. });
  15950. const pField = FormField.parts.field({ factory: { sketch: factory } });
  15951. return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
  15952. };
  15953. const image = image => new Promise((resolve, reject) => {
  15954. const loaded = () => {
  15955. destroy();
  15956. resolve(image);
  15957. };
  15958. const listeners = [
  15959. bind(image, 'load', loaded),
  15960. bind(image, 'error', () => {
  15961. destroy();
  15962. reject('Unable to load data from image: ' + image.dom.src);
  15963. })
  15964. ];
  15965. const destroy = () => each$1(listeners, l => l.unbind());
  15966. if (image.dom.complete) {
  15967. loaded();
  15968. }
  15969. });
  15970. const calculateImagePosition = (panelWidth, panelHeight, imageWidth, imageHeight, zoom) => {
  15971. const width = imageWidth * zoom;
  15972. const height = imageHeight * zoom;
  15973. const left = Math.max(0, panelWidth / 2 - width / 2);
  15974. const top = Math.max(0, panelHeight / 2 - height / 2);
  15975. return {
  15976. left: left.toString() + 'px',
  15977. top: top.toString() + 'px',
  15978. width: width.toString() + 'px',
  15979. height: height.toString() + 'px'
  15980. };
  15981. };
  15982. const zoomToFit = (panel, width, height) => {
  15983. const panelW = get$c(panel);
  15984. const panelH = get$d(panel);
  15985. return Math.min(panelW / width, panelH / height, 1);
  15986. };
  15987. const renderImagePreview = (spec, initialData) => {
  15988. const cachedData = Cell(initialData.getOr({ url: '' }));
  15989. const memImage = record({
  15990. dom: {
  15991. tag: 'img',
  15992. classes: ['tox-imagepreview__image'],
  15993. attributes: initialData.map(data => ({ src: data.url })).getOr({})
  15994. }
  15995. });
  15996. const memContainer = record({
  15997. dom: {
  15998. tag: 'div',
  15999. classes: ['tox-imagepreview__container'],
  16000. attributes: { role: 'presentation' }
  16001. },
  16002. components: [memImage.asSpec()]
  16003. });
  16004. const setValue = (frameComponent, data) => {
  16005. const translatedData = { url: data.url };
  16006. data.zoom.each(z => translatedData.zoom = z);
  16007. data.cachedWidth.each(z => translatedData.cachedWidth = z);
  16008. data.cachedHeight.each(z => translatedData.cachedHeight = z);
  16009. cachedData.set(translatedData);
  16010. const applyFramePositioning = () => {
  16011. const {cachedWidth, cachedHeight, zoom} = translatedData;
  16012. if (!isUndefined(cachedWidth) && !isUndefined(cachedHeight)) {
  16013. if (isUndefined(zoom)) {
  16014. const z = zoomToFit(frameComponent.element, cachedWidth, cachedHeight);
  16015. translatedData.zoom = z;
  16016. }
  16017. const position = calculateImagePosition(get$c(frameComponent.element), get$d(frameComponent.element), cachedWidth, cachedHeight, translatedData.zoom);
  16018. memContainer.getOpt(frameComponent).each(container => {
  16019. setAll(container.element, position);
  16020. });
  16021. }
  16022. };
  16023. memImage.getOpt(frameComponent).each(imageComponent => {
  16024. const img = imageComponent.element;
  16025. if (data.url !== get$f(img, 'src')) {
  16026. set$9(img, 'src', data.url);
  16027. remove$2(frameComponent.element, 'tox-imagepreview__loaded');
  16028. }
  16029. applyFramePositioning();
  16030. image(img).then(img => {
  16031. if (frameComponent.getSystem().isConnected()) {
  16032. add$2(frameComponent.element, 'tox-imagepreview__loaded');
  16033. translatedData.cachedWidth = img.dom.naturalWidth;
  16034. translatedData.cachedHeight = img.dom.naturalHeight;
  16035. applyFramePositioning();
  16036. }
  16037. });
  16038. });
  16039. };
  16040. const styles = {};
  16041. spec.height.each(h => styles.height = h);
  16042. const fakeValidatedData = initialData.map(d => ({
  16043. url: d.url,
  16044. zoom: Optional.from(d.zoom),
  16045. cachedWidth: Optional.from(d.cachedWidth),
  16046. cachedHeight: Optional.from(d.cachedHeight)
  16047. }));
  16048. return {
  16049. dom: {
  16050. tag: 'div',
  16051. classes: ['tox-imagepreview'],
  16052. styles,
  16053. attributes: { role: 'presentation' }
  16054. },
  16055. components: [memContainer.asSpec()],
  16056. behaviours: derive$1([
  16057. ComposingConfigs.self(),
  16058. withComp(fakeValidatedData, () => cachedData.get(), setValue)
  16059. ])
  16060. };
  16061. };
  16062. const renderLabel$2 = (spec, backstageShared) => {
  16063. const baseClass = 'tox-label';
  16064. const centerClass = spec.align === 'center' ? [`${ baseClass }--center`] : [];
  16065. const endClass = spec.align === 'end' ? [`${ baseClass }--end`] : [];
  16066. const label = {
  16067. dom: {
  16068. tag: 'label',
  16069. classes: [
  16070. baseClass,
  16071. ...centerClass,
  16072. ...endClass
  16073. ]
  16074. },
  16075. components: [text$2(backstageShared.providers.translate(spec.label))]
  16076. };
  16077. const comps = map$2(spec.items, backstageShared.interpreter);
  16078. return {
  16079. dom: {
  16080. tag: 'div',
  16081. classes: ['tox-form__group']
  16082. },
  16083. components: [
  16084. label,
  16085. ...comps
  16086. ],
  16087. behaviours: derive$1([
  16088. ComposingConfigs.self(),
  16089. Replacing.config({}),
  16090. domHtml(Optional.none()),
  16091. Keying.config({ mode: 'acyclic' })
  16092. ])
  16093. };
  16094. };
  16095. const internalToolbarButtonExecute = generate$6('toolbar.button.execute');
  16096. const onToolbarButtonExecute = info => runOnExecute$1((comp, _simulatedEvent) => {
  16097. runWithApi(info, comp)(itemApi => {
  16098. emitWith(comp, internalToolbarButtonExecute, { buttonApi: itemApi });
  16099. info.onAction(itemApi);
  16100. });
  16101. });
  16102. const commonButtonDisplayEvent = generate$6('common-button-display-events');
  16103. const toolbarButtonEventOrder = {
  16104. [execute$5()]: [
  16105. 'disabling',
  16106. 'alloy.base.behaviour',
  16107. 'toggling',
  16108. 'toolbar-button-events'
  16109. ],
  16110. [attachedToDom()]: [
  16111. 'toolbar-button-events',
  16112. commonButtonDisplayEvent
  16113. ],
  16114. [mousedown()]: [
  16115. 'focusing',
  16116. 'alloy.base.behaviour',
  16117. commonButtonDisplayEvent
  16118. ]
  16119. };
  16120. const forceInitialSize = comp => set$8(comp.element, 'width', get$e(comp.element, 'width'));
  16121. const renderIcon$1 = (iconName, iconsProvider, behaviours) => render$3(iconName, {
  16122. tag: 'span',
  16123. classes: [
  16124. 'tox-icon',
  16125. 'tox-tbtn__icon-wrap'
  16126. ],
  16127. behaviours
  16128. }, iconsProvider);
  16129. const renderIconFromPack$1 = (iconName, iconsProvider) => renderIcon$1(iconName, iconsProvider, []);
  16130. const renderReplaceableIconFromPack = (iconName, iconsProvider) => renderIcon$1(iconName, iconsProvider, [Replacing.config({})]);
  16131. const renderLabel$1 = (text, prefix, providersBackstage) => ({
  16132. dom: {
  16133. tag: 'span',
  16134. classes: [`${ prefix }__select-label`]
  16135. },
  16136. components: [text$2(providersBackstage.translate(text))],
  16137. behaviours: derive$1([Replacing.config({})])
  16138. });
  16139. const updateMenuText = generate$6('update-menu-text');
  16140. const updateMenuIcon = generate$6('update-menu-icon');
  16141. const renderCommonDropdown = (spec, prefix, sharedBackstage) => {
  16142. const editorOffCell = Cell(noop);
  16143. const optMemDisplayText = spec.text.map(text => record(renderLabel$1(text, prefix, sharedBackstage.providers)));
  16144. const optMemDisplayIcon = spec.icon.map(iconName => record(renderReplaceableIconFromPack(iconName, sharedBackstage.providers.icons)));
  16145. const onLeftOrRightInMenu = (comp, se) => {
  16146. const dropdown = Representing.getValue(comp);
  16147. Focusing.focus(dropdown);
  16148. emitWith(dropdown, 'keydown', { raw: se.event.raw });
  16149. Dropdown.close(dropdown);
  16150. return Optional.some(true);
  16151. };
  16152. const role = spec.role.fold(() => ({}), role => ({ role }));
  16153. const tooltipAttributes = spec.tooltip.fold(() => ({}), tooltip => {
  16154. const translatedTooltip = sharedBackstage.providers.translate(tooltip);
  16155. return {
  16156. 'title': translatedTooltip,
  16157. 'aria-label': translatedTooltip
  16158. };
  16159. });
  16160. const iconSpec = render$3('chevron-down', {
  16161. tag: 'div',
  16162. classes: [`${ prefix }__select-chevron`]
  16163. }, sharedBackstage.providers.icons);
  16164. const fixWidthBehaviourName = generate$6('common-button-display-events');
  16165. const memDropdown = record(Dropdown.sketch({
  16166. ...spec.uid ? { uid: spec.uid } : {},
  16167. ...role,
  16168. dom: {
  16169. tag: 'button',
  16170. classes: [
  16171. prefix,
  16172. `${ prefix }--select`
  16173. ].concat(map$2(spec.classes, c => `${ prefix }--${ c }`)),
  16174. attributes: { ...tooltipAttributes }
  16175. },
  16176. components: componentRenderPipeline([
  16177. optMemDisplayIcon.map(mem => mem.asSpec()),
  16178. optMemDisplayText.map(mem => mem.asSpec()),
  16179. Optional.some(iconSpec)
  16180. ]),
  16181. matchWidth: true,
  16182. useMinWidth: true,
  16183. onOpen: (anchor, dropdownComp, tmenuComp) => {
  16184. if (spec.searchable) {
  16185. focusSearchField(tmenuComp);
  16186. }
  16187. },
  16188. dropdownBehaviours: derive$1([
  16189. ...spec.dropdownBehaviours,
  16190. DisablingConfigs.button(() => spec.disabled || sharedBackstage.providers.isDisabled()),
  16191. receivingConfig(),
  16192. Unselecting.config({}),
  16193. Replacing.config({}),
  16194. config('dropdown-events', [
  16195. onControlAttached(spec, editorOffCell),
  16196. onControlDetached(spec, editorOffCell)
  16197. ]),
  16198. config(fixWidthBehaviourName, [runOnAttached((comp, _se) => forceInitialSize(comp))]),
  16199. config('menubutton-update-display-text', [
  16200. run$1(updateMenuText, (comp, se) => {
  16201. optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
  16202. Replacing.set(displayText, [text$2(sharedBackstage.providers.translate(se.event.text))]);
  16203. });
  16204. }),
  16205. run$1(updateMenuIcon, (comp, se) => {
  16206. optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
  16207. Replacing.set(displayIcon, [renderReplaceableIconFromPack(se.event.icon, sharedBackstage.providers.icons)]);
  16208. });
  16209. })
  16210. ])
  16211. ]),
  16212. eventOrder: deepMerge(toolbarButtonEventOrder, {
  16213. mousedown: [
  16214. 'focusing',
  16215. 'alloy.base.behaviour',
  16216. 'item-type-events',
  16217. 'normal-dropdown-events'
  16218. ],
  16219. [attachedToDom()]: [
  16220. 'toolbar-button-events',
  16221. 'dropdown-events',
  16222. fixWidthBehaviourName
  16223. ]
  16224. }),
  16225. sandboxBehaviours: derive$1([
  16226. Keying.config({
  16227. mode: 'special',
  16228. onLeft: onLeftOrRightInMenu,
  16229. onRight: onLeftOrRightInMenu
  16230. }),
  16231. config('dropdown-sandbox-events', [
  16232. run$1(refetchTriggerEvent, (originalSandboxComp, se) => {
  16233. handleRefetchTrigger(originalSandboxComp);
  16234. se.stop();
  16235. }),
  16236. run$1(redirectMenuItemInteractionEvent, (sandboxComp, se) => {
  16237. handleRedirectToMenuItem(sandboxComp, se);
  16238. se.stop();
  16239. })
  16240. ])
  16241. ]),
  16242. lazySink: sharedBackstage.getSink,
  16243. toggleClass: `${ prefix }--active`,
  16244. parts: {
  16245. menu: {
  16246. ...part(false, spec.columns, spec.presets),
  16247. fakeFocus: spec.searchable,
  16248. onHighlightItem: updateAriaOnHighlight,
  16249. onCollapseMenu: (tmenuComp, itemCompCausingCollapse, nowActiveMenuComp) => {
  16250. Highlighting.getHighlighted(nowActiveMenuComp).each(itemComp => {
  16251. updateAriaOnHighlight(tmenuComp, nowActiveMenuComp, itemComp);
  16252. });
  16253. },
  16254. onDehighlightItem: updateAriaOnDehighlight
  16255. }
  16256. },
  16257. getAnchorOverrides: () => {
  16258. return {
  16259. maxHeightFunction: (element, available) => {
  16260. anchored()(element, available - 10);
  16261. }
  16262. };
  16263. },
  16264. fetch: comp => Future.nu(curry(spec.fetch, comp))
  16265. }));
  16266. return memDropdown.asSpec();
  16267. };
  16268. const isMenuItemReference = item => isString(item);
  16269. const isSeparator$2 = item => item.type === 'separator';
  16270. const isExpandingMenuItem = item => has$2(item, 'getSubmenuItems');
  16271. const separator$2 = { type: 'separator' };
  16272. const unwrapReferences = (items, menuItems) => {
  16273. const realItems = foldl(items, (acc, item) => {
  16274. if (isMenuItemReference(item)) {
  16275. if (item === '') {
  16276. return acc;
  16277. } else if (item === '|') {
  16278. return acc.length > 0 && !isSeparator$2(acc[acc.length - 1]) ? acc.concat([separator$2]) : acc;
  16279. } else if (has$2(menuItems, item.toLowerCase())) {
  16280. return acc.concat([menuItems[item.toLowerCase()]]);
  16281. } else {
  16282. return acc;
  16283. }
  16284. } else {
  16285. return acc.concat([item]);
  16286. }
  16287. }, []);
  16288. if (realItems.length > 0 && isSeparator$2(realItems[realItems.length - 1])) {
  16289. realItems.pop();
  16290. }
  16291. return realItems;
  16292. };
  16293. const getFromExpandingItem = (item, menuItems) => {
  16294. const submenuItems = item.getSubmenuItems();
  16295. const rest = expand(submenuItems, menuItems);
  16296. const newMenus = deepMerge(rest.menus, { [item.value]: rest.items });
  16297. const newExpansions = deepMerge(rest.expansions, { [item.value]: item.value });
  16298. return {
  16299. item,
  16300. menus: newMenus,
  16301. expansions: newExpansions
  16302. };
  16303. };
  16304. const generateValueIfRequired = item => {
  16305. const itemValue = get$g(item, 'value').getOrThunk(() => generate$6('generated-menu-item'));
  16306. return deepMerge({ value: itemValue }, item);
  16307. };
  16308. const expand = (items, menuItems) => {
  16309. const realItems = unwrapReferences(isString(items) ? items.split(' ') : items, menuItems);
  16310. return foldr(realItems, (acc, item) => {
  16311. if (isExpandingMenuItem(item)) {
  16312. const itemWithValue = generateValueIfRequired(item);
  16313. const newData = getFromExpandingItem(itemWithValue, menuItems);
  16314. return {
  16315. menus: deepMerge(acc.menus, newData.menus),
  16316. items: [
  16317. newData.item,
  16318. ...acc.items
  16319. ],
  16320. expansions: deepMerge(acc.expansions, newData.expansions)
  16321. };
  16322. } else {
  16323. return {
  16324. ...acc,
  16325. items: [
  16326. item,
  16327. ...acc.items
  16328. ]
  16329. };
  16330. }
  16331. }, {
  16332. menus: {},
  16333. expansions: {},
  16334. items: []
  16335. });
  16336. };
  16337. const getSearchModeForField = settings => {
  16338. return settings.search.fold(() => ({ searchMode: 'no-search' }), searchSettings => ({
  16339. searchMode: 'search-with-field',
  16340. placeholder: searchSettings.placeholder
  16341. }));
  16342. };
  16343. const getSearchModeForResults = settings => {
  16344. return settings.search.fold(() => ({ searchMode: 'no-search' }), _ => ({ searchMode: 'search-with-results' }));
  16345. };
  16346. const build = (items, itemResponse, backstage, settings) => {
  16347. const primary = generate$6('primary-menu');
  16348. const data = expand(items, backstage.shared.providers.menuItems());
  16349. if (data.items.length === 0) {
  16350. return Optional.none();
  16351. }
  16352. const mainMenuSearchMode = getSearchModeForField(settings);
  16353. const mainMenu = createPartialMenu(primary, data.items, itemResponse, backstage, settings.isHorizontalMenu, mainMenuSearchMode);
  16354. const submenuSearchMode = getSearchModeForResults(settings);
  16355. const submenus = map$1(data.menus, (menuItems, menuName) => createPartialMenu(menuName, menuItems, itemResponse, backstage, false, submenuSearchMode));
  16356. const menus = deepMerge(submenus, wrap$1(primary, mainMenu));
  16357. return Optional.from(tieredMenu.tieredData(primary, menus, data.expansions));
  16358. };
  16359. const isSingleListItem = item => !has$2(item, 'items');
  16360. const dataAttribute = 'data-value';
  16361. const fetchItems = (dropdownComp, name, items, selectedValue) => map$2(items, item => {
  16362. if (!isSingleListItem(item)) {
  16363. return {
  16364. type: 'nestedmenuitem',
  16365. text: item.text,
  16366. getSubmenuItems: () => fetchItems(dropdownComp, name, item.items, selectedValue)
  16367. };
  16368. } else {
  16369. return {
  16370. type: 'togglemenuitem',
  16371. text: item.text,
  16372. value: item.value,
  16373. active: item.value === selectedValue,
  16374. onAction: () => {
  16375. Representing.setValue(dropdownComp, item.value);
  16376. emitWith(dropdownComp, formChangeEvent, { name });
  16377. Focusing.focus(dropdownComp);
  16378. }
  16379. };
  16380. }
  16381. });
  16382. const findItemByValue = (items, value) => findMap(items, item => {
  16383. if (!isSingleListItem(item)) {
  16384. return findItemByValue(item.items, value);
  16385. } else {
  16386. return someIf(item.value === value, item);
  16387. }
  16388. });
  16389. const renderListBox = (spec, backstage, initialData) => {
  16390. const providersBackstage = backstage.shared.providers;
  16391. const initialItem = initialData.bind(value => findItemByValue(spec.items, value)).orThunk(() => head(spec.items).filter(isSingleListItem));
  16392. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  16393. const pField = FormField.parts.field({
  16394. dom: {},
  16395. factory: {
  16396. sketch: sketchSpec => renderCommonDropdown({
  16397. uid: sketchSpec.uid,
  16398. text: initialItem.map(item => item.text),
  16399. icon: Optional.none(),
  16400. tooltip: spec.label,
  16401. role: Optional.none(),
  16402. fetch: (comp, callback) => {
  16403. const items = fetchItems(comp, spec.name, spec.items, Representing.getValue(comp));
  16404. callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
  16405. isHorizontalMenu: false,
  16406. search: Optional.none()
  16407. }));
  16408. },
  16409. onSetup: constant$1(noop),
  16410. getApi: constant$1({}),
  16411. columns: 1,
  16412. presets: 'normal',
  16413. classes: [],
  16414. dropdownBehaviours: [
  16415. Tabstopping.config({}),
  16416. withComp(initialItem.map(item => item.value), comp => get$f(comp.element, dataAttribute), (comp, data) => {
  16417. findItemByValue(spec.items, data).each(item => {
  16418. set$9(comp.element, dataAttribute, item.value);
  16419. emitWith(comp, updateMenuText, { text: item.text });
  16420. });
  16421. })
  16422. ]
  16423. }, 'tox-listbox', backstage.shared)
  16424. }
  16425. });
  16426. const listBoxWrap = {
  16427. dom: {
  16428. tag: 'div',
  16429. classes: ['tox-listboxfield']
  16430. },
  16431. components: [pField]
  16432. };
  16433. return FormField.sketch({
  16434. dom: {
  16435. tag: 'div',
  16436. classes: ['tox-form__group']
  16437. },
  16438. components: flatten([
  16439. pLabel.toArray(),
  16440. [listBoxWrap]
  16441. ]),
  16442. fieldBehaviours: derive$1([Disabling.config({
  16443. disabled: constant$1(!spec.enabled),
  16444. onDisabled: comp => {
  16445. FormField.getField(comp).each(Disabling.disable);
  16446. },
  16447. onEnabled: comp => {
  16448. FormField.getField(comp).each(Disabling.enable);
  16449. }
  16450. })])
  16451. });
  16452. };
  16453. const renderPanel = (spec, backstage) => ({
  16454. dom: {
  16455. tag: 'div',
  16456. classes: spec.classes
  16457. },
  16458. components: map$2(spec.items, backstage.shared.interpreter)
  16459. });
  16460. const factory$h = (detail, _spec) => {
  16461. const options = map$2(detail.options, option => ({
  16462. dom: {
  16463. tag: 'option',
  16464. value: option.value,
  16465. innerHtml: option.text
  16466. }
  16467. }));
  16468. const initialValues = detail.data.map(v => wrap$1('initialValue', v)).getOr({});
  16469. return {
  16470. uid: detail.uid,
  16471. dom: {
  16472. tag: 'select',
  16473. classes: detail.selectClasses,
  16474. attributes: detail.selectAttributes
  16475. },
  16476. components: options,
  16477. behaviours: augment(detail.selectBehaviours, [
  16478. Focusing.config({}),
  16479. Representing.config({
  16480. store: {
  16481. mode: 'manual',
  16482. getValue: select => {
  16483. return get$6(select.element);
  16484. },
  16485. setValue: (select, newValue) => {
  16486. const firstOption = head(detail.options);
  16487. const found = find$5(detail.options, opt => opt.value === newValue);
  16488. if (found.isSome()) {
  16489. set$5(select.element, newValue);
  16490. } else if (select.element.dom.selectedIndex === -1 && newValue === '') {
  16491. firstOption.each(value => set$5(select.element, value.value));
  16492. }
  16493. },
  16494. ...initialValues
  16495. }
  16496. })
  16497. ])
  16498. };
  16499. };
  16500. const HtmlSelect = single({
  16501. name: 'HtmlSelect',
  16502. configFields: [
  16503. required$1('options'),
  16504. field('selectBehaviours', [
  16505. Focusing,
  16506. Representing
  16507. ]),
  16508. defaulted('selectClasses', []),
  16509. defaulted('selectAttributes', {}),
  16510. option$3('data')
  16511. ],
  16512. factory: factory$h
  16513. });
  16514. const renderSelectBox = (spec, providersBackstage, initialData) => {
  16515. const translatedOptions = map$2(spec.items, item => ({
  16516. text: providersBackstage.translate(item.text),
  16517. value: item.value
  16518. }));
  16519. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  16520. const pField = FormField.parts.field({
  16521. dom: {},
  16522. ...initialData.map(data => ({ data })).getOr({}),
  16523. selectAttributes: { size: spec.size },
  16524. options: translatedOptions,
  16525. factory: HtmlSelect,
  16526. selectBehaviours: derive$1([
  16527. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  16528. Tabstopping.config({}),
  16529. config('selectbox-change', [run$1(change(), (component, _) => {
  16530. emitWith(component, formChangeEvent, { name: spec.name });
  16531. })])
  16532. ])
  16533. });
  16534. const chevron = spec.size > 1 ? Optional.none() : Optional.some(render$3('chevron-down', {
  16535. tag: 'div',
  16536. classes: ['tox-selectfield__icon-js']
  16537. }, providersBackstage.icons));
  16538. const selectWrap = {
  16539. dom: {
  16540. tag: 'div',
  16541. classes: ['tox-selectfield']
  16542. },
  16543. components: flatten([
  16544. [pField],
  16545. chevron.toArray()
  16546. ])
  16547. };
  16548. return FormField.sketch({
  16549. dom: {
  16550. tag: 'div',
  16551. classes: ['tox-form__group']
  16552. },
  16553. components: flatten([
  16554. pLabel.toArray(),
  16555. [selectWrap]
  16556. ]),
  16557. fieldBehaviours: derive$1([
  16558. Disabling.config({
  16559. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  16560. onDisabled: comp => {
  16561. FormField.getField(comp).each(Disabling.disable);
  16562. },
  16563. onEnabled: comp => {
  16564. FormField.getField(comp).each(Disabling.enable);
  16565. }
  16566. }),
  16567. receivingConfig()
  16568. ])
  16569. });
  16570. };
  16571. const schema$h = constant$1([
  16572. defaulted('field1Name', 'field1'),
  16573. defaulted('field2Name', 'field2'),
  16574. onStrictHandler('onLockedChange'),
  16575. markers$1(['lockClass']),
  16576. defaulted('locked', false),
  16577. SketchBehaviours.field('coupledFieldBehaviours', [
  16578. Composing,
  16579. Representing
  16580. ])
  16581. ]);
  16582. const getField = (comp, detail, partName) => getPart(comp, detail, partName).bind(Composing.getCurrent);
  16583. const coupledPart = (selfName, otherName) => required({
  16584. factory: FormField,
  16585. name: selfName,
  16586. overrides: detail => {
  16587. return {
  16588. fieldBehaviours: derive$1([config('coupled-input-behaviour', [run$1(input(), me => {
  16589. getField(me, detail, otherName).each(other => {
  16590. getPart(me, detail, 'lock').each(lock => {
  16591. if (Toggling.isOn(lock)) {
  16592. detail.onLockedChange(me, other, lock);
  16593. }
  16594. });
  16595. });
  16596. })])])
  16597. };
  16598. }
  16599. });
  16600. const parts$c = constant$1([
  16601. coupledPart('field1', 'field2'),
  16602. coupledPart('field2', 'field1'),
  16603. required({
  16604. factory: Button,
  16605. schema: [required$1('dom')],
  16606. name: 'lock',
  16607. overrides: detail => {
  16608. return {
  16609. buttonBehaviours: derive$1([Toggling.config({
  16610. selected: detail.locked,
  16611. toggleClass: detail.markers.lockClass,
  16612. aria: { mode: 'pressed' }
  16613. })])
  16614. };
  16615. }
  16616. })
  16617. ]);
  16618. const factory$g = (detail, components, _spec, _externals) => ({
  16619. uid: detail.uid,
  16620. dom: detail.dom,
  16621. components,
  16622. behaviours: SketchBehaviours.augment(detail.coupledFieldBehaviours, [
  16623. Composing.config({ find: Optional.some }),
  16624. Representing.config({
  16625. store: {
  16626. mode: 'manual',
  16627. getValue: comp => {
  16628. const parts = getPartsOrDie(comp, detail, [
  16629. 'field1',
  16630. 'field2'
  16631. ]);
  16632. return {
  16633. [detail.field1Name]: Representing.getValue(parts.field1()),
  16634. [detail.field2Name]: Representing.getValue(parts.field2())
  16635. };
  16636. },
  16637. setValue: (comp, value) => {
  16638. const parts = getPartsOrDie(comp, detail, [
  16639. 'field1',
  16640. 'field2'
  16641. ]);
  16642. if (hasNonNullableKey(value, detail.field1Name)) {
  16643. Representing.setValue(parts.field1(), value[detail.field1Name]);
  16644. }
  16645. if (hasNonNullableKey(value, detail.field2Name)) {
  16646. Representing.setValue(parts.field2(), value[detail.field2Name]);
  16647. }
  16648. }
  16649. }
  16650. })
  16651. ]),
  16652. apis: {
  16653. getField1: component => getPart(component, detail, 'field1'),
  16654. getField2: component => getPart(component, detail, 'field2'),
  16655. getLock: component => getPart(component, detail, 'lock')
  16656. }
  16657. });
  16658. const FormCoupledInputs = composite({
  16659. name: 'FormCoupledInputs',
  16660. configFields: schema$h(),
  16661. partFields: parts$c(),
  16662. factory: factory$g,
  16663. apis: {
  16664. getField1: (apis, component) => apis.getField1(component),
  16665. getField2: (apis, component) => apis.getField2(component),
  16666. getLock: (apis, component) => apis.getLock(component)
  16667. }
  16668. });
  16669. const formatSize = size => {
  16670. const unitDec = {
  16671. '': 0,
  16672. 'px': 0,
  16673. 'pt': 1,
  16674. 'mm': 1,
  16675. 'pc': 2,
  16676. 'ex': 2,
  16677. 'em': 2,
  16678. 'ch': 2,
  16679. 'rem': 2,
  16680. 'cm': 3,
  16681. 'in': 4,
  16682. '%': 4
  16683. };
  16684. const maxDecimal = unit => unit in unitDec ? unitDec[unit] : 1;
  16685. let numText = size.value.toFixed(maxDecimal(size.unit));
  16686. if (numText.indexOf('.') !== -1) {
  16687. numText = numText.replace(/\.?0*$/, '');
  16688. }
  16689. return numText + size.unit;
  16690. };
  16691. const parseSize = sizeText => {
  16692. const numPattern = /^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/;
  16693. const match = numPattern.exec(sizeText);
  16694. if (match !== null) {
  16695. const value = parseFloat(match[1]);
  16696. const unit = match[2];
  16697. return Result.value({
  16698. value,
  16699. unit
  16700. });
  16701. } else {
  16702. return Result.error(sizeText);
  16703. }
  16704. };
  16705. const convertUnit = (size, unit) => {
  16706. const inInch = {
  16707. '': 96,
  16708. 'px': 96,
  16709. 'pt': 72,
  16710. 'cm': 2.54,
  16711. 'pc': 12,
  16712. 'mm': 25.4,
  16713. 'in': 1
  16714. };
  16715. const supported = u => has$2(inInch, u);
  16716. if (size.unit === unit) {
  16717. return Optional.some(size.value);
  16718. } else if (supported(size.unit) && supported(unit)) {
  16719. if (inInch[size.unit] === inInch[unit]) {
  16720. return Optional.some(size.value);
  16721. } else {
  16722. return Optional.some(size.value / inInch[size.unit] * inInch[unit]);
  16723. }
  16724. } else {
  16725. return Optional.none();
  16726. }
  16727. };
  16728. const noSizeConversion = _input => Optional.none();
  16729. const ratioSizeConversion = (scale, unit) => size => convertUnit(size, unit).map(value => ({
  16730. value: value * scale,
  16731. unit
  16732. }));
  16733. const makeRatioConverter = (currentFieldText, otherFieldText) => {
  16734. const cValue = parseSize(currentFieldText).toOptional();
  16735. const oValue = parseSize(otherFieldText).toOptional();
  16736. return lift2(cValue, oValue, (cSize, oSize) => convertUnit(cSize, oSize.unit).map(val => oSize.value / val).map(r => ratioSizeConversion(r, oSize.unit)).getOr(noSizeConversion)).getOr(noSizeConversion);
  16737. };
  16738. const renderSizeInput = (spec, providersBackstage) => {
  16739. let converter = noSizeConversion;
  16740. const ratioEvent = generate$6('ratio-event');
  16741. const makeIcon = iconName => render$3(iconName, {
  16742. tag: 'span',
  16743. classes: [
  16744. 'tox-icon',
  16745. 'tox-lock-icon__' + iconName
  16746. ]
  16747. }, providersBackstage.icons);
  16748. const pLock = FormCoupledInputs.parts.lock({
  16749. dom: {
  16750. tag: 'button',
  16751. classes: [
  16752. 'tox-lock',
  16753. 'tox-button',
  16754. 'tox-button--naked',
  16755. 'tox-button--icon'
  16756. ],
  16757. attributes: { title: providersBackstage.translate(spec.label.getOr('Constrain proportions')) }
  16758. },
  16759. components: [
  16760. makeIcon('lock'),
  16761. makeIcon('unlock')
  16762. ],
  16763. buttonBehaviours: derive$1([
  16764. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  16765. receivingConfig(),
  16766. Tabstopping.config({})
  16767. ])
  16768. });
  16769. const formGroup = components => ({
  16770. dom: {
  16771. tag: 'div',
  16772. classes: ['tox-form__group']
  16773. },
  16774. components
  16775. });
  16776. const getFieldPart = isField1 => FormField.parts.field({
  16777. factory: Input,
  16778. inputClasses: ['tox-textfield'],
  16779. inputBehaviours: derive$1([
  16780. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  16781. receivingConfig(),
  16782. Tabstopping.config({}),
  16783. config('size-input-events', [
  16784. run$1(focusin(), (component, _simulatedEvent) => {
  16785. emitWith(component, ratioEvent, { isField1 });
  16786. }),
  16787. run$1(change(), (component, _simulatedEvent) => {
  16788. emitWith(component, formChangeEvent, { name: spec.name });
  16789. })
  16790. ])
  16791. ]),
  16792. selectOnFocus: false
  16793. });
  16794. const getLabel = label => ({
  16795. dom: {
  16796. tag: 'label',
  16797. classes: ['tox-label']
  16798. },
  16799. components: [text$2(providersBackstage.translate(label))]
  16800. });
  16801. const widthField = FormCoupledInputs.parts.field1(formGroup([
  16802. FormField.parts.label(getLabel('Width')),
  16803. getFieldPart(true)
  16804. ]));
  16805. const heightField = FormCoupledInputs.parts.field2(formGroup([
  16806. FormField.parts.label(getLabel('Height')),
  16807. getFieldPart(false)
  16808. ]));
  16809. return FormCoupledInputs.sketch({
  16810. dom: {
  16811. tag: 'div',
  16812. classes: ['tox-form__group']
  16813. },
  16814. components: [{
  16815. dom: {
  16816. tag: 'div',
  16817. classes: ['tox-form__controls-h-stack']
  16818. },
  16819. components: [
  16820. widthField,
  16821. heightField,
  16822. formGroup([
  16823. getLabel(nbsp),
  16824. pLock
  16825. ])
  16826. ]
  16827. }],
  16828. field1Name: 'width',
  16829. field2Name: 'height',
  16830. locked: true,
  16831. markers: { lockClass: 'tox-locked' },
  16832. onLockedChange: (current, other, _lock) => {
  16833. parseSize(Representing.getValue(current)).each(size => {
  16834. converter(size).each(newSize => {
  16835. Representing.setValue(other, formatSize(newSize));
  16836. });
  16837. });
  16838. },
  16839. coupledFieldBehaviours: derive$1([
  16840. Disabling.config({
  16841. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  16842. onDisabled: comp => {
  16843. FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
  16844. FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
  16845. FormCoupledInputs.getLock(comp).each(Disabling.disable);
  16846. },
  16847. onEnabled: comp => {
  16848. FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
  16849. FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
  16850. FormCoupledInputs.getLock(comp).each(Disabling.enable);
  16851. }
  16852. }),
  16853. receivingConfig(),
  16854. config('size-input-events2', [run$1(ratioEvent, (component, simulatedEvent) => {
  16855. const isField1 = simulatedEvent.event.isField1;
  16856. const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
  16857. const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
  16858. const value1 = optCurrent.map(Representing.getValue).getOr('');
  16859. const value2 = optOther.map(Representing.getValue).getOr('');
  16860. converter = makeRatioConverter(value1, value2);
  16861. })])
  16862. ])
  16863. });
  16864. };
  16865. const renderSlider = (spec, providerBackstage, initialData) => {
  16866. const labelPart = Slider.parts.label({
  16867. dom: {
  16868. tag: 'label',
  16869. classes: ['tox-label']
  16870. },
  16871. components: [text$2(providerBackstage.translate(spec.label))]
  16872. });
  16873. const spectrum = Slider.parts.spectrum({
  16874. dom: {
  16875. tag: 'div',
  16876. classes: ['tox-slider__rail'],
  16877. attributes: { role: 'presentation' }
  16878. }
  16879. });
  16880. const thumb = Slider.parts.thumb({
  16881. dom: {
  16882. tag: 'div',
  16883. classes: ['tox-slider__handle'],
  16884. attributes: { role: 'presentation' }
  16885. }
  16886. });
  16887. return Slider.sketch({
  16888. dom: {
  16889. tag: 'div',
  16890. classes: ['tox-slider'],
  16891. attributes: { role: 'presentation' }
  16892. },
  16893. model: {
  16894. mode: 'x',
  16895. minX: spec.min,
  16896. maxX: spec.max,
  16897. getInitialValue: constant$1(initialData.getOrThunk(() => (Math.abs(spec.max) - Math.abs(spec.min)) / 2))
  16898. },
  16899. components: [
  16900. labelPart,
  16901. spectrum,
  16902. thumb
  16903. ],
  16904. sliderBehaviours: derive$1([
  16905. ComposingConfigs.self(),
  16906. Focusing.config({})
  16907. ]),
  16908. onChoose: (component, thumb, value) => {
  16909. emitWith(component, formChangeEvent, {
  16910. name: spec.name,
  16911. value
  16912. });
  16913. }
  16914. });
  16915. };
  16916. const renderTable = (spec, providersBackstage) => {
  16917. const renderTh = text => ({
  16918. dom: {
  16919. tag: 'th',
  16920. innerHtml: providersBackstage.translate(text)
  16921. }
  16922. });
  16923. const renderHeader = header => ({
  16924. dom: { tag: 'thead' },
  16925. components: [{
  16926. dom: { tag: 'tr' },
  16927. components: map$2(header, renderTh)
  16928. }]
  16929. });
  16930. const renderTd = text => ({
  16931. dom: {
  16932. tag: 'td',
  16933. innerHtml: providersBackstage.translate(text)
  16934. }
  16935. });
  16936. const renderTr = row => ({
  16937. dom: { tag: 'tr' },
  16938. components: map$2(row, renderTd)
  16939. });
  16940. const renderRows = rows => ({
  16941. dom: { tag: 'tbody' },
  16942. components: map$2(rows, renderTr)
  16943. });
  16944. return {
  16945. dom: {
  16946. tag: 'table',
  16947. classes: ['tox-dialog__table']
  16948. },
  16949. components: [
  16950. renderHeader(spec.header),
  16951. renderRows(spec.cells)
  16952. ],
  16953. behaviours: derive$1([
  16954. Tabstopping.config({}),
  16955. Focusing.config({})
  16956. ])
  16957. };
  16958. };
  16959. const renderTextField = (spec, providersBackstage) => {
  16960. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  16961. const baseInputBehaviours = [
  16962. Disabling.config({ disabled: () => spec.disabled || providersBackstage.isDisabled() }),
  16963. receivingConfig(),
  16964. Keying.config({
  16965. mode: 'execution',
  16966. useEnter: spec.multiline !== true,
  16967. useControlEnter: spec.multiline === true,
  16968. execute: comp => {
  16969. emit(comp, formSubmitEvent);
  16970. return Optional.some(true);
  16971. }
  16972. }),
  16973. config('textfield-change', [
  16974. run$1(input(), (component, _) => {
  16975. emitWith(component, formChangeEvent, { name: spec.name });
  16976. }),
  16977. run$1(postPaste(), (component, _) => {
  16978. emitWith(component, formChangeEvent, { name: spec.name });
  16979. })
  16980. ]),
  16981. Tabstopping.config({})
  16982. ];
  16983. const validatingBehaviours = spec.validation.map(vl => Invalidating.config({
  16984. getRoot: input => {
  16985. return parentElement(input.element);
  16986. },
  16987. invalidClass: 'tox-invalid',
  16988. validator: {
  16989. validate: input => {
  16990. const v = Representing.getValue(input);
  16991. const result = vl.validator(v);
  16992. return Future.pure(result === true ? Result.value(v) : Result.error(result));
  16993. },
  16994. validateOnLoad: vl.validateOnLoad
  16995. }
  16996. })).toArray();
  16997. const placeholder = spec.placeholder.fold(constant$1({}), p => ({ placeholder: providersBackstage.translate(p) }));
  16998. const inputMode = spec.inputMode.fold(constant$1({}), mode => ({ inputmode: mode }));
  16999. const inputAttributes = {
  17000. ...placeholder,
  17001. ...inputMode
  17002. };
  17003. const pField = FormField.parts.field({
  17004. tag: spec.multiline === true ? 'textarea' : 'input',
  17005. ...spec.data.map(data => ({ data })).getOr({}),
  17006. inputAttributes,
  17007. inputClasses: [spec.classname],
  17008. inputBehaviours: derive$1(flatten([
  17009. baseInputBehaviours,
  17010. validatingBehaviours
  17011. ])),
  17012. selectOnFocus: false,
  17013. factory: Input
  17014. });
  17015. const pTextField = spec.multiline ? {
  17016. dom: {
  17017. tag: 'div',
  17018. classes: ['tox-textarea-wrap']
  17019. },
  17020. components: [pField]
  17021. } : pField;
  17022. const extraClasses = spec.flex ? ['tox-form__group--stretched'] : [];
  17023. const extraClasses2 = extraClasses.concat(spec.maximized ? ['tox-form-group--maximize'] : []);
  17024. const extraBehaviours = [
  17025. Disabling.config({
  17026. disabled: () => spec.disabled || providersBackstage.isDisabled(),
  17027. onDisabled: comp => {
  17028. FormField.getField(comp).each(Disabling.disable);
  17029. },
  17030. onEnabled: comp => {
  17031. FormField.getField(comp).each(Disabling.enable);
  17032. }
  17033. }),
  17034. receivingConfig()
  17035. ];
  17036. return renderFormFieldWith(pLabel, pTextField, extraClasses2, extraBehaviours);
  17037. };
  17038. const renderInput = (spec, providersBackstage, initialData) => renderTextField({
  17039. name: spec.name,
  17040. multiline: false,
  17041. label: spec.label,
  17042. inputMode: spec.inputMode,
  17043. placeholder: spec.placeholder,
  17044. flex: false,
  17045. disabled: !spec.enabled,
  17046. classname: 'tox-textfield',
  17047. validation: Optional.none(),
  17048. maximized: spec.maximized,
  17049. data: initialData
  17050. }, providersBackstage);
  17051. const renderTextarea = (spec, providersBackstage, initialData) => renderTextField({
  17052. name: spec.name,
  17053. multiline: true,
  17054. label: spec.label,
  17055. inputMode: Optional.none(),
  17056. placeholder: spec.placeholder,
  17057. flex: true,
  17058. disabled: !spec.enabled,
  17059. classname: 'tox-textarea',
  17060. validation: Optional.none(),
  17061. maximized: spec.maximized,
  17062. data: initialData
  17063. }, providersBackstage);
  17064. const getAnimationRoot = (component, slideConfig) => slideConfig.getAnimationRoot.fold(() => component.element, get => get(component));
  17065. const getDimensionProperty = slideConfig => slideConfig.dimension.property;
  17066. const getDimension = (slideConfig, elem) => slideConfig.dimension.getDimension(elem);
  17067. const disableTransitions = (component, slideConfig) => {
  17068. const root = getAnimationRoot(component, slideConfig);
  17069. remove$1(root, [
  17070. slideConfig.shrinkingClass,
  17071. slideConfig.growingClass
  17072. ]);
  17073. };
  17074. const setShrunk = (component, slideConfig) => {
  17075. remove$2(component.element, slideConfig.openClass);
  17076. add$2(component.element, slideConfig.closedClass);
  17077. set$8(component.element, getDimensionProperty(slideConfig), '0px');
  17078. reflow(component.element);
  17079. };
  17080. const setGrown = (component, slideConfig) => {
  17081. remove$2(component.element, slideConfig.closedClass);
  17082. add$2(component.element, slideConfig.openClass);
  17083. remove$6(component.element, getDimensionProperty(slideConfig));
  17084. };
  17085. const doImmediateShrink = (component, slideConfig, slideState, _calculatedSize) => {
  17086. slideState.setCollapsed();
  17087. set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
  17088. disableTransitions(component, slideConfig);
  17089. setShrunk(component, slideConfig);
  17090. slideConfig.onStartShrink(component);
  17091. slideConfig.onShrunk(component);
  17092. };
  17093. const doStartShrink = (component, slideConfig, slideState, calculatedSize) => {
  17094. const size = calculatedSize.getOrThunk(() => getDimension(slideConfig, component.element));
  17095. slideState.setCollapsed();
  17096. set$8(component.element, getDimensionProperty(slideConfig), size);
  17097. reflow(component.element);
  17098. const root = getAnimationRoot(component, slideConfig);
  17099. remove$2(root, slideConfig.growingClass);
  17100. add$2(root, slideConfig.shrinkingClass);
  17101. setShrunk(component, slideConfig);
  17102. slideConfig.onStartShrink(component);
  17103. };
  17104. const doStartSmartShrink = (component, slideConfig, slideState) => {
  17105. const size = getDimension(slideConfig, component.element);
  17106. const shrinker = size === '0px' ? doImmediateShrink : doStartShrink;
  17107. shrinker(component, slideConfig, slideState, Optional.some(size));
  17108. };
  17109. const doStartGrow = (component, slideConfig, slideState) => {
  17110. const root = getAnimationRoot(component, slideConfig);
  17111. const wasShrinking = has(root, slideConfig.shrinkingClass);
  17112. const beforeSize = getDimension(slideConfig, component.element);
  17113. setGrown(component, slideConfig);
  17114. const fullSize = getDimension(slideConfig, component.element);
  17115. const startPartialGrow = () => {
  17116. set$8(component.element, getDimensionProperty(slideConfig), beforeSize);
  17117. reflow(component.element);
  17118. };
  17119. const startCompleteGrow = () => {
  17120. setShrunk(component, slideConfig);
  17121. };
  17122. const setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow;
  17123. setStartSize();
  17124. remove$2(root, slideConfig.shrinkingClass);
  17125. add$2(root, slideConfig.growingClass);
  17126. setGrown(component, slideConfig);
  17127. set$8(component.element, getDimensionProperty(slideConfig), fullSize);
  17128. slideState.setExpanded();
  17129. slideConfig.onStartGrow(component);
  17130. };
  17131. const refresh$4 = (component, slideConfig, slideState) => {
  17132. if (slideState.isExpanded()) {
  17133. remove$6(component.element, getDimensionProperty(slideConfig));
  17134. const fullSize = getDimension(slideConfig, component.element);
  17135. set$8(component.element, getDimensionProperty(slideConfig), fullSize);
  17136. }
  17137. };
  17138. const grow = (component, slideConfig, slideState) => {
  17139. if (!slideState.isExpanded()) {
  17140. doStartGrow(component, slideConfig, slideState);
  17141. }
  17142. };
  17143. const shrink = (component, slideConfig, slideState) => {
  17144. if (slideState.isExpanded()) {
  17145. doStartSmartShrink(component, slideConfig, slideState);
  17146. }
  17147. };
  17148. const immediateShrink = (component, slideConfig, slideState) => {
  17149. if (slideState.isExpanded()) {
  17150. doImmediateShrink(component, slideConfig, slideState);
  17151. }
  17152. };
  17153. const hasGrown = (component, slideConfig, slideState) => slideState.isExpanded();
  17154. const hasShrunk = (component, slideConfig, slideState) => slideState.isCollapsed();
  17155. const isGrowing = (component, slideConfig, _slideState) => {
  17156. const root = getAnimationRoot(component, slideConfig);
  17157. return has(root, slideConfig.growingClass) === true;
  17158. };
  17159. const isShrinking = (component, slideConfig, _slideState) => {
  17160. const root = getAnimationRoot(component, slideConfig);
  17161. return has(root, slideConfig.shrinkingClass) === true;
  17162. };
  17163. const isTransitioning = (component, slideConfig, slideState) => isGrowing(component, slideConfig) || isShrinking(component, slideConfig);
  17164. const toggleGrow = (component, slideConfig, slideState) => {
  17165. const f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow;
  17166. f(component, slideConfig, slideState);
  17167. };
  17168. const immediateGrow = (component, slideConfig, slideState) => {
  17169. if (!slideState.isExpanded()) {
  17170. setGrown(component, slideConfig);
  17171. set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
  17172. disableTransitions(component, slideConfig);
  17173. slideState.setExpanded();
  17174. slideConfig.onStartGrow(component);
  17175. slideConfig.onGrown(component);
  17176. }
  17177. };
  17178. var SlidingApis = /*#__PURE__*/Object.freeze({
  17179. __proto__: null,
  17180. refresh: refresh$4,
  17181. grow: grow,
  17182. shrink: shrink,
  17183. immediateShrink: immediateShrink,
  17184. hasGrown: hasGrown,
  17185. hasShrunk: hasShrunk,
  17186. isGrowing: isGrowing,
  17187. isShrinking: isShrinking,
  17188. isTransitioning: isTransitioning,
  17189. toggleGrow: toggleGrow,
  17190. disableTransitions: disableTransitions,
  17191. immediateGrow: immediateGrow
  17192. });
  17193. const exhibit = (base, slideConfig, _slideState) => {
  17194. const expanded = slideConfig.expanded;
  17195. return expanded ? nu$7({
  17196. classes: [slideConfig.openClass],
  17197. styles: {}
  17198. }) : nu$7({
  17199. classes: [slideConfig.closedClass],
  17200. styles: wrap$1(slideConfig.dimension.property, '0px')
  17201. });
  17202. };
  17203. const events$6 = (slideConfig, slideState) => derive$2([runOnSource(transitionend(), (component, simulatedEvent) => {
  17204. const raw = simulatedEvent.event.raw;
  17205. if (raw.propertyName === slideConfig.dimension.property) {
  17206. disableTransitions(component, slideConfig);
  17207. if (slideState.isExpanded()) {
  17208. remove$6(component.element, slideConfig.dimension.property);
  17209. }
  17210. const notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk;
  17211. notify(component);
  17212. }
  17213. })]);
  17214. var ActiveSliding = /*#__PURE__*/Object.freeze({
  17215. __proto__: null,
  17216. exhibit: exhibit,
  17217. events: events$6
  17218. });
  17219. var SlidingSchema = [
  17220. required$1('closedClass'),
  17221. required$1('openClass'),
  17222. required$1('shrinkingClass'),
  17223. required$1('growingClass'),
  17224. option$3('getAnimationRoot'),
  17225. onHandler('onShrunk'),
  17226. onHandler('onStartShrink'),
  17227. onHandler('onGrown'),
  17228. onHandler('onStartGrow'),
  17229. defaulted('expanded', false),
  17230. requiredOf('dimension', choose$1('property', {
  17231. width: [
  17232. output$1('property', 'width'),
  17233. output$1('getDimension', elem => get$c(elem) + 'px')
  17234. ],
  17235. height: [
  17236. output$1('property', 'height'),
  17237. output$1('getDimension', elem => get$d(elem) + 'px')
  17238. ]
  17239. }))
  17240. ];
  17241. const init$9 = spec => {
  17242. const state = Cell(spec.expanded);
  17243. const readState = () => 'expanded: ' + state.get();
  17244. return nu$8({
  17245. isExpanded: () => state.get() === true,
  17246. isCollapsed: () => state.get() === false,
  17247. setCollapsed: curry(state.set, false),
  17248. setExpanded: curry(state.set, true),
  17249. readState
  17250. });
  17251. };
  17252. var SlidingState = /*#__PURE__*/Object.freeze({
  17253. __proto__: null,
  17254. init: init$9
  17255. });
  17256. const Sliding = create$4({
  17257. fields: SlidingSchema,
  17258. name: 'sliding',
  17259. active: ActiveSliding,
  17260. apis: SlidingApis,
  17261. state: SlidingState
  17262. });
  17263. const getMenuButtonApi = component => ({
  17264. isEnabled: () => !Disabling.isDisabled(component),
  17265. setEnabled: state => Disabling.set(component, !state),
  17266. setActive: state => {
  17267. const elm = component.element;
  17268. if (state) {
  17269. add$2(elm, 'tox-tbtn--enabled');
  17270. set$9(elm, 'aria-pressed', true);
  17271. } else {
  17272. remove$2(elm, 'tox-tbtn--enabled');
  17273. remove$7(elm, 'aria-pressed');
  17274. }
  17275. },
  17276. isActive: () => has(component.element, 'tox-tbtn--enabled'),
  17277. setText: text => {
  17278. emitWith(component, updateMenuText, { text });
  17279. },
  17280. setIcon: icon => emitWith(component, updateMenuIcon, { icon })
  17281. });
  17282. const renderMenuButton = (spec, prefix, backstage, role, tabstopping = true) => {
  17283. return renderCommonDropdown({
  17284. text: spec.text,
  17285. icon: spec.icon,
  17286. tooltip: spec.tooltip,
  17287. searchable: spec.search.isSome(),
  17288. role,
  17289. fetch: (dropdownComp, callback) => {
  17290. const fetchContext = { pattern: spec.search.isSome() ? getSearchPattern(dropdownComp) : '' };
  17291. spec.fetch(items => {
  17292. callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
  17293. isHorizontalMenu: false,
  17294. search: spec.search
  17295. }));
  17296. }, fetchContext, getMenuButtonApi(dropdownComp));
  17297. },
  17298. onSetup: spec.onSetup,
  17299. getApi: getMenuButtonApi,
  17300. columns: 1,
  17301. presets: 'normal',
  17302. classes: [],
  17303. dropdownBehaviours: [...tabstopping ? [Tabstopping.config({})] : []]
  17304. }, prefix, backstage.shared);
  17305. };
  17306. const getFetch = (items, getButton, backstage) => {
  17307. const getMenuItemAction = item => api => {
  17308. const newValue = !api.isActive();
  17309. api.setActive(newValue);
  17310. item.storage.set(newValue);
  17311. backstage.shared.getSink().each(sink => {
  17312. getButton().getOpt(sink).each(orig => {
  17313. focus$3(orig.element);
  17314. emitWith(orig, formActionEvent, {
  17315. name: item.name,
  17316. value: item.storage.get()
  17317. });
  17318. });
  17319. });
  17320. };
  17321. const getMenuItemSetup = item => api => {
  17322. api.setActive(item.storage.get());
  17323. };
  17324. return success => {
  17325. success(map$2(items, item => {
  17326. const text = item.text.fold(() => ({}), text => ({ text }));
  17327. return {
  17328. type: item.type,
  17329. active: false,
  17330. ...text,
  17331. onAction: getMenuItemAction(item),
  17332. onSetup: getMenuItemSetup(item)
  17333. };
  17334. }));
  17335. };
  17336. };
  17337. const renderLabel = text => ({
  17338. dom: {
  17339. tag: 'span',
  17340. classes: ['tox-tree__label'],
  17341. attributes: {
  17342. 'title': text,
  17343. 'aria-label': text
  17344. }
  17345. },
  17346. components: [text$2(text)]
  17347. });
  17348. const leafLabelEventsId = generate$6('leaf-label-event-id');
  17349. const renderLeafLabel = ({leaf, onLeafAction, visible, treeId, selectedId, backstage}) => {
  17350. const internalMenuButton = leaf.menu.map(btn => renderMenuButton(btn, 'tox-mbtn', backstage, Optional.none(), visible));
  17351. const components = [renderLabel(leaf.title)];
  17352. internalMenuButton.each(btn => components.push(btn));
  17353. return Button.sketch({
  17354. dom: {
  17355. tag: 'div',
  17356. classes: [
  17357. 'tox-tree--leaf__label',
  17358. 'tox-trbtn'
  17359. ].concat(visible ? ['tox-tree--leaf__label--visible'] : [])
  17360. },
  17361. components,
  17362. role: 'treeitem',
  17363. action: button => {
  17364. onLeafAction(leaf.id);
  17365. button.getSystem().broadcastOn([`update-active-item-${ treeId }`], { value: leaf.id });
  17366. },
  17367. eventOrder: {
  17368. [keydown()]: [
  17369. leafLabelEventsId,
  17370. 'keying'
  17371. ]
  17372. },
  17373. buttonBehaviours: derive$1([
  17374. ...visible ? [Tabstopping.config({})] : [],
  17375. Toggling.config({
  17376. toggleClass: 'tox-trbtn--enabled',
  17377. toggleOnExecute: false,
  17378. aria: { mode: 'selected' }
  17379. }),
  17380. Receiving.config({
  17381. channels: {
  17382. [`update-active-item-${ treeId }`]: {
  17383. onReceive: (comp, message) => {
  17384. (message.value === leaf.id ? Toggling.on : Toggling.off)(comp);
  17385. }
  17386. }
  17387. }
  17388. }),
  17389. config(leafLabelEventsId, [
  17390. runOnAttached((comp, _se) => {
  17391. selectedId.each(id => {
  17392. const toggle = id === leaf.id ? Toggling.on : Toggling.off;
  17393. toggle(comp);
  17394. });
  17395. }),
  17396. run$1(keydown(), (comp, se) => {
  17397. const isLeftArrowKey = se.event.raw.code === 'ArrowLeft';
  17398. const isRightArrowKey = se.event.raw.code === 'ArrowRight';
  17399. if (isLeftArrowKey) {
  17400. ancestor(comp.element, '.tox-tree--directory').each(dirElement => {
  17401. comp.getSystem().getByDom(dirElement).each(dirComp => {
  17402. child(dirElement, '.tox-tree--directory__label').each(dirLabelElement => {
  17403. dirComp.getSystem().getByDom(dirLabelElement).each(Focusing.focus);
  17404. });
  17405. });
  17406. });
  17407. se.stop();
  17408. } else if (isRightArrowKey) {
  17409. se.stop();
  17410. }
  17411. })
  17412. ])
  17413. ])
  17414. });
  17415. };
  17416. const renderIcon = (iconName, iconsProvider, behaviours) => render$3(iconName, {
  17417. tag: 'span',
  17418. classes: [
  17419. 'tox-tree__icon-wrap',
  17420. 'tox-icon'
  17421. ],
  17422. behaviours
  17423. }, iconsProvider);
  17424. const renderIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, []);
  17425. const directoryLabelEventsId = generate$6('directory-label-event-id');
  17426. const renderDirectoryLabel = ({directory, visible, noChildren, backstage}) => {
  17427. const internalMenuButton = directory.menu.map(btn => renderMenuButton(btn, 'tox-mbtn', backstage, Optional.none()));
  17428. const components = [
  17429. {
  17430. dom: {
  17431. tag: 'div',
  17432. classes: ['tox-chevron']
  17433. },
  17434. components: [renderIconFromPack('chevron-right', backstage.shared.providers.icons)]
  17435. },
  17436. renderLabel(directory.title)
  17437. ];
  17438. internalMenuButton.each(btn => {
  17439. components.push(btn);
  17440. });
  17441. const toggleExpandChildren = button => {
  17442. ancestor(button.element, '.tox-tree--directory').each(directoryEle => {
  17443. button.getSystem().getByDom(directoryEle).each(directoryComp => {
  17444. const willExpand = !Toggling.isOn(directoryComp);
  17445. Toggling.toggle(directoryComp);
  17446. emitWith(button, 'expand-tree-node', {
  17447. expanded: willExpand,
  17448. node: directory.id
  17449. });
  17450. });
  17451. });
  17452. };
  17453. return Button.sketch({
  17454. dom: {
  17455. tag: 'div',
  17456. classes: [
  17457. 'tox-tree--directory__label',
  17458. 'tox-trbtn'
  17459. ].concat(visible ? ['tox-tree--directory__label--visible'] : [])
  17460. },
  17461. components,
  17462. action: toggleExpandChildren,
  17463. eventOrder: {
  17464. [keydown()]: [
  17465. directoryLabelEventsId,
  17466. 'keying'
  17467. ]
  17468. },
  17469. buttonBehaviours: derive$1([
  17470. ...visible ? [Tabstopping.config({})] : [],
  17471. config(directoryLabelEventsId, [run$1(keydown(), (comp, se) => {
  17472. const isRightArrowKey = se.event.raw.code === 'ArrowRight';
  17473. const isLeftArrowKey = se.event.raw.code === 'ArrowLeft';
  17474. if (isRightArrowKey && noChildren) {
  17475. se.stop();
  17476. }
  17477. if (isRightArrowKey || isLeftArrowKey) {
  17478. ancestor(comp.element, '.tox-tree--directory').each(directoryEle => {
  17479. comp.getSystem().getByDom(directoryEle).each(directoryComp => {
  17480. if (!Toggling.isOn(directoryComp) && isRightArrowKey || Toggling.isOn(directoryComp) && isLeftArrowKey) {
  17481. toggleExpandChildren(comp);
  17482. se.stop();
  17483. } else if (isLeftArrowKey && !Toggling.isOn(directoryComp)) {
  17484. ancestor(directoryComp.element, '.tox-tree--directory').each(parentDirElement => {
  17485. child(parentDirElement, '.tox-tree--directory__label').each(parentDirLabelElement => {
  17486. directoryComp.getSystem().getByDom(parentDirLabelElement).each(Focusing.focus);
  17487. });
  17488. });
  17489. se.stop();
  17490. }
  17491. });
  17492. });
  17493. }
  17494. })])
  17495. ])
  17496. });
  17497. };
  17498. const renderDirectoryChildren = ({children, onLeafAction, visible, treeId, expandedIds, selectedId, backstage}) => {
  17499. return {
  17500. dom: {
  17501. tag: 'div',
  17502. classes: ['tox-tree--directory__children']
  17503. },
  17504. components: children.map(item => {
  17505. return item.type === 'leaf' ? renderLeafLabel({
  17506. leaf: item,
  17507. selectedId,
  17508. onLeafAction,
  17509. visible,
  17510. treeId,
  17511. backstage
  17512. }) : renderDirectory({
  17513. directory: item,
  17514. expandedIds,
  17515. selectedId,
  17516. onLeafAction,
  17517. labelTabstopping: visible,
  17518. treeId,
  17519. backstage
  17520. });
  17521. }),
  17522. behaviours: derive$1([
  17523. Sliding.config({
  17524. dimension: { property: 'height' },
  17525. closedClass: 'tox-tree--directory__children--closed',
  17526. openClass: 'tox-tree--directory__children--open',
  17527. growingClass: 'tox-tree--directory__children--growing',
  17528. shrinkingClass: 'tox-tree--directory__children--shrinking',
  17529. expanded: visible
  17530. }),
  17531. Replacing.config({})
  17532. ])
  17533. };
  17534. };
  17535. const directoryEventsId = generate$6('directory-event-id');
  17536. const renderDirectory = ({directory, onLeafAction, labelTabstopping, treeId, backstage, expandedIds, selectedId}) => {
  17537. const {children} = directory;
  17538. const expandedIdsCell = Cell(expandedIds);
  17539. const computedChildrenComponents = visible => children.map(item => {
  17540. return item.type === 'leaf' ? renderLeafLabel({
  17541. leaf: item,
  17542. selectedId,
  17543. onLeafAction,
  17544. visible,
  17545. treeId,
  17546. backstage
  17547. }) : renderDirectory({
  17548. directory: item,
  17549. expandedIds: expandedIdsCell.get(),
  17550. selectedId,
  17551. onLeafAction,
  17552. labelTabstopping: visible,
  17553. treeId,
  17554. backstage
  17555. });
  17556. });
  17557. const childrenVisible = expandedIds.includes(directory.id);
  17558. return {
  17559. dom: {
  17560. tag: 'div',
  17561. classes: ['tox-tree--directory'],
  17562. attributes: { role: 'treeitem' }
  17563. },
  17564. components: [
  17565. renderDirectoryLabel({
  17566. directory,
  17567. visible: labelTabstopping,
  17568. noChildren: directory.children.length === 0,
  17569. backstage
  17570. }),
  17571. renderDirectoryChildren({
  17572. children,
  17573. expandedIds,
  17574. selectedId,
  17575. onLeafAction,
  17576. visible: childrenVisible,
  17577. treeId,
  17578. backstage
  17579. })
  17580. ],
  17581. behaviours: derive$1([
  17582. config(directoryEventsId, [
  17583. runOnAttached((comp, _se) => {
  17584. Toggling.set(comp, childrenVisible);
  17585. }),
  17586. run$1('expand-tree-node', (_cmp, se) => {
  17587. const {expanded, node} = se.event;
  17588. expandedIdsCell.set(expanded ? [
  17589. ...expandedIdsCell.get(),
  17590. node
  17591. ] : expandedIdsCell.get().filter(id => id !== node));
  17592. })
  17593. ]),
  17594. Toggling.config({
  17595. ...directory.children.length > 0 ? { aria: { mode: 'expanded' } } : {},
  17596. toggleClass: 'tox-tree--directory--expanded',
  17597. onToggled: (comp, childrenVisible) => {
  17598. const childrenComp = comp.components()[1];
  17599. const newChildren = computedChildrenComponents(childrenVisible);
  17600. if (childrenVisible) {
  17601. Sliding.grow(childrenComp);
  17602. } else {
  17603. Sliding.shrink(childrenComp);
  17604. }
  17605. Replacing.set(childrenComp, newChildren);
  17606. }
  17607. })
  17608. ])
  17609. };
  17610. };
  17611. const treeEventsId = generate$6('tree-event-id');
  17612. const renderTree = (spec, backstage) => {
  17613. const onLeafAction = spec.onLeafAction.getOr(noop);
  17614. const onToggleExpand = spec.onToggleExpand.getOr(noop);
  17615. const defaultExpandedIds = spec.defaultExpandedIds;
  17616. const expandedIds = Cell(defaultExpandedIds);
  17617. const selectedIdCell = Cell(spec.defaultSelectedId);
  17618. const treeId = generate$6('tree-id');
  17619. const children = (selectedId, expandedIds) => spec.items.map(item => {
  17620. return item.type === 'leaf' ? renderLeafLabel({
  17621. leaf: item,
  17622. selectedId,
  17623. onLeafAction,
  17624. visible: true,
  17625. treeId,
  17626. backstage
  17627. }) : renderDirectory({
  17628. directory: item,
  17629. selectedId,
  17630. onLeafAction,
  17631. expandedIds,
  17632. labelTabstopping: true,
  17633. treeId,
  17634. backstage
  17635. });
  17636. });
  17637. return {
  17638. dom: {
  17639. tag: 'div',
  17640. classes: ['tox-tree'],
  17641. attributes: { role: 'tree' }
  17642. },
  17643. components: children(selectedIdCell.get(), expandedIds.get()),
  17644. behaviours: derive$1([
  17645. Keying.config({
  17646. mode: 'flow',
  17647. selector: '.tox-tree--leaf__label--visible, .tox-tree--directory__label--visible',
  17648. cycles: false
  17649. }),
  17650. config(treeEventsId, [run$1('expand-tree-node', (_cmp, se) => {
  17651. const {expanded, node} = se.event;
  17652. expandedIds.set(expanded ? [
  17653. ...expandedIds.get(),
  17654. node
  17655. ] : expandedIds.get().filter(id => id !== node));
  17656. onToggleExpand(expandedIds.get(), {
  17657. expanded,
  17658. node
  17659. });
  17660. })]),
  17661. Receiving.config({
  17662. channels: {
  17663. [`update-active-item-${ treeId }`]: {
  17664. onReceive: (comp, message) => {
  17665. selectedIdCell.set(Optional.some(message.value));
  17666. Replacing.set(comp, children(Optional.some(message.value), expandedIds.get()));
  17667. }
  17668. }
  17669. }
  17670. }),
  17671. Replacing.config({})
  17672. ])
  17673. };
  17674. };
  17675. const events$5 = (streamConfig, streamState) => {
  17676. const streams = streamConfig.stream.streams;
  17677. const processor = streams.setup(streamConfig, streamState);
  17678. return derive$2([
  17679. run$1(streamConfig.event, processor),
  17680. runOnDetached(() => streamState.cancel())
  17681. ].concat(streamConfig.cancelEvent.map(e => [run$1(e, () => streamState.cancel())]).getOr([])));
  17682. };
  17683. var ActiveStreaming = /*#__PURE__*/Object.freeze({
  17684. __proto__: null,
  17685. events: events$5
  17686. });
  17687. const throttle = _config => {
  17688. const state = Cell(null);
  17689. const readState = () => ({ timer: state.get() !== null ? 'set' : 'unset' });
  17690. const setTimer = t => {
  17691. state.set(t);
  17692. };
  17693. const cancel = () => {
  17694. const t = state.get();
  17695. if (t !== null) {
  17696. t.cancel();
  17697. }
  17698. };
  17699. return nu$8({
  17700. readState,
  17701. setTimer,
  17702. cancel
  17703. });
  17704. };
  17705. const init$8 = spec => spec.stream.streams.state(spec);
  17706. var StreamingState = /*#__PURE__*/Object.freeze({
  17707. __proto__: null,
  17708. throttle: throttle,
  17709. init: init$8
  17710. });
  17711. const setup$c = (streamInfo, streamState) => {
  17712. const sInfo = streamInfo.stream;
  17713. const throttler = last(streamInfo.onStream, sInfo.delay);
  17714. streamState.setTimer(throttler);
  17715. return (component, simulatedEvent) => {
  17716. throttler.throttle(component, simulatedEvent);
  17717. if (sInfo.stopEvent) {
  17718. simulatedEvent.stop();
  17719. }
  17720. };
  17721. };
  17722. var StreamingSchema = [
  17723. requiredOf('stream', choose$1('mode', {
  17724. throttle: [
  17725. required$1('delay'),
  17726. defaulted('stopEvent', true),
  17727. output$1('streams', {
  17728. setup: setup$c,
  17729. state: throttle
  17730. })
  17731. ]
  17732. })),
  17733. defaulted('event', 'input'),
  17734. option$3('cancelEvent'),
  17735. onStrictHandler('onStream')
  17736. ];
  17737. const Streaming = create$4({
  17738. fields: StreamingSchema,
  17739. name: 'streaming',
  17740. active: ActiveStreaming,
  17741. state: StreamingState
  17742. });
  17743. const setValueFromItem = (model, input, item) => {
  17744. const itemData = Representing.getValue(item);
  17745. Representing.setValue(input, itemData);
  17746. setCursorAtEnd(input);
  17747. };
  17748. const setSelectionOn = (input, f) => {
  17749. const el = input.element;
  17750. const value = get$6(el);
  17751. const node = el.dom;
  17752. if (get$f(el, 'type') !== 'number') {
  17753. f(node, value);
  17754. }
  17755. };
  17756. const setCursorAtEnd = input => {
  17757. setSelectionOn(input, (node, value) => node.setSelectionRange(value.length, value.length));
  17758. };
  17759. const setSelectionToEnd = (input, startOffset) => {
  17760. setSelectionOn(input, (node, value) => node.setSelectionRange(startOffset, value.length));
  17761. };
  17762. const attemptSelectOver = (model, input, item) => {
  17763. if (!model.selectsOver) {
  17764. return Optional.none();
  17765. } else {
  17766. const currentValue = Representing.getValue(input);
  17767. const inputDisplay = model.getDisplayText(currentValue);
  17768. const itemValue = Representing.getValue(item);
  17769. const itemDisplay = model.getDisplayText(itemValue);
  17770. return itemDisplay.indexOf(inputDisplay) === 0 ? Optional.some(() => {
  17771. setValueFromItem(model, input, item);
  17772. setSelectionToEnd(input, inputDisplay.length);
  17773. }) : Optional.none();
  17774. }
  17775. };
  17776. const itemExecute = constant$1('alloy.typeahead.itemexecute');
  17777. const make$3 = (detail, components, spec, externals) => {
  17778. const navigateList = (comp, simulatedEvent, highlighter) => {
  17779. detail.previewing.set(false);
  17780. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  17781. if (Sandboxing.isOpen(sandbox)) {
  17782. Composing.getCurrent(sandbox).each(menu => {
  17783. Highlighting.getHighlighted(menu).fold(() => {
  17784. highlighter(menu);
  17785. }, () => {
  17786. dispatchEvent(sandbox, menu.element, 'keydown', simulatedEvent);
  17787. });
  17788. });
  17789. } else {
  17790. const onOpenSync = sandbox => {
  17791. Composing.getCurrent(sandbox).each(highlighter);
  17792. };
  17793. open(detail, mapFetch(comp), comp, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  17794. }
  17795. };
  17796. const focusBehaviours$1 = focusBehaviours(detail);
  17797. const mapFetch = comp => tdata => tdata.map(data => {
  17798. const menus = values(data.menus);
  17799. const items = bind$3(menus, menu => filter$2(menu.items, item => item.type === 'item'));
  17800. const repState = Representing.getState(comp);
  17801. repState.update(map$2(items, item => item.data));
  17802. return data;
  17803. });
  17804. const getActiveMenu = sandboxComp => Composing.getCurrent(sandboxComp);
  17805. const typeaheadCustomEvents = 'typeaheadevents';
  17806. const behaviours = [
  17807. Focusing.config({}),
  17808. Representing.config({
  17809. onSetValue: detail.onSetValue,
  17810. store: {
  17811. mode: 'dataset',
  17812. getDataKey: comp => get$6(comp.element),
  17813. getFallbackEntry: itemString => ({
  17814. value: itemString,
  17815. meta: {}
  17816. }),
  17817. setValue: (comp, data) => {
  17818. set$5(comp.element, detail.model.getDisplayText(data));
  17819. },
  17820. ...detail.initialData.map(d => wrap$1('initialValue', d)).getOr({})
  17821. }
  17822. }),
  17823. Streaming.config({
  17824. stream: {
  17825. mode: 'throttle',
  17826. delay: detail.responseTime,
  17827. stopEvent: false
  17828. },
  17829. onStream: (component, _simulatedEvent) => {
  17830. const sandbox = Coupling.getCoupled(component, 'sandbox');
  17831. const focusInInput = Focusing.isFocused(component);
  17832. if (focusInInput) {
  17833. if (get$6(component.element).length >= detail.minChars) {
  17834. const previousValue = getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu).map(Representing.getValue));
  17835. detail.previewing.set(true);
  17836. const onOpenSync = _sandbox => {
  17837. getActiveMenu(sandbox).each(activeMenu => {
  17838. previousValue.fold(() => {
  17839. if (detail.model.selectsOver) {
  17840. Highlighting.highlightFirst(activeMenu);
  17841. }
  17842. }, pv => {
  17843. Highlighting.highlightBy(activeMenu, item => {
  17844. const itemData = Representing.getValue(item);
  17845. return itemData.value === pv.value;
  17846. });
  17847. Highlighting.getHighlighted(activeMenu).orThunk(() => {
  17848. Highlighting.highlightFirst(activeMenu);
  17849. return Optional.none();
  17850. });
  17851. });
  17852. });
  17853. };
  17854. open(detail, mapFetch(component), component, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightJustMenu).get(noop);
  17855. }
  17856. }
  17857. },
  17858. cancelEvent: typeaheadCancel()
  17859. }),
  17860. Keying.config({
  17861. mode: 'special',
  17862. onDown: (comp, simulatedEvent) => {
  17863. navigateList(comp, simulatedEvent, Highlighting.highlightFirst);
  17864. return Optional.some(true);
  17865. },
  17866. onEscape: comp => {
  17867. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  17868. if (Sandboxing.isOpen(sandbox)) {
  17869. Sandboxing.close(sandbox);
  17870. return Optional.some(true);
  17871. }
  17872. return Optional.none();
  17873. },
  17874. onUp: (comp, simulatedEvent) => {
  17875. navigateList(comp, simulatedEvent, Highlighting.highlightLast);
  17876. return Optional.some(true);
  17877. },
  17878. onEnter: comp => {
  17879. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  17880. const sandboxIsOpen = Sandboxing.isOpen(sandbox);
  17881. if (sandboxIsOpen && !detail.previewing.get()) {
  17882. return getActiveMenu(sandbox).bind(activeMenu => Highlighting.getHighlighted(activeMenu)).map(item => {
  17883. emitWith(comp, itemExecute(), { item });
  17884. return true;
  17885. });
  17886. } else {
  17887. const currentValue = Representing.getValue(comp);
  17888. emit(comp, typeaheadCancel());
  17889. detail.onExecute(sandbox, comp, currentValue);
  17890. if (sandboxIsOpen) {
  17891. Sandboxing.close(sandbox);
  17892. }
  17893. return Optional.some(true);
  17894. }
  17895. }
  17896. }),
  17897. Toggling.config({
  17898. toggleClass: detail.markers.openClass,
  17899. aria: { mode: 'expanded' }
  17900. }),
  17901. Coupling.config({
  17902. others: {
  17903. sandbox: hotspot => {
  17904. return makeSandbox$1(detail, hotspot, {
  17905. onOpen: () => Toggling.on(hotspot),
  17906. onClose: () => {
  17907. detail.lazyTypeaheadComp.get().each(input => remove$7(input.element, 'aria-activedescendant'));
  17908. Toggling.off(hotspot);
  17909. }
  17910. });
  17911. }
  17912. }
  17913. }),
  17914. config(typeaheadCustomEvents, [
  17915. runOnAttached(typeaheadComp => {
  17916. detail.lazyTypeaheadComp.set(Optional.some(typeaheadComp));
  17917. }),
  17918. runOnDetached(_typeaheadComp => {
  17919. detail.lazyTypeaheadComp.set(Optional.none());
  17920. }),
  17921. runOnExecute$1(comp => {
  17922. const onOpenSync = noop;
  17923. togglePopup(detail, mapFetch(comp), comp, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  17924. }),
  17925. run$1(itemExecute(), (comp, se) => {
  17926. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  17927. setValueFromItem(detail.model, comp, se.event.item);
  17928. emit(comp, typeaheadCancel());
  17929. detail.onItemExecute(comp, sandbox, se.event.item, Representing.getValue(comp));
  17930. Sandboxing.close(sandbox);
  17931. setCursorAtEnd(comp);
  17932. })
  17933. ].concat(detail.dismissOnBlur ? [run$1(postBlur(), typeahead => {
  17934. const sandbox = Coupling.getCoupled(typeahead, 'sandbox');
  17935. if (search(sandbox.element).isNone()) {
  17936. Sandboxing.close(sandbox);
  17937. }
  17938. })] : []))
  17939. ];
  17940. const eventOrder = {
  17941. [detachedFromDom()]: [
  17942. Representing.name(),
  17943. Streaming.name(),
  17944. typeaheadCustomEvents
  17945. ],
  17946. ...detail.eventOrder
  17947. };
  17948. return {
  17949. uid: detail.uid,
  17950. dom: dom(deepMerge(detail, {
  17951. inputAttributes: {
  17952. 'role': 'combobox',
  17953. 'aria-autocomplete': 'list',
  17954. 'aria-haspopup': 'true'
  17955. }
  17956. })),
  17957. behaviours: {
  17958. ...focusBehaviours$1,
  17959. ...augment(detail.typeaheadBehaviours, behaviours)
  17960. },
  17961. eventOrder
  17962. };
  17963. };
  17964. const schema$g = constant$1([
  17965. option$3('lazySink'),
  17966. required$1('fetch'),
  17967. defaulted('minChars', 5),
  17968. defaulted('responseTime', 1000),
  17969. onHandler('onOpen'),
  17970. defaulted('getHotspot', Optional.some),
  17971. defaulted('getAnchorOverrides', constant$1({})),
  17972. defaulted('layouts', Optional.none()),
  17973. defaulted('eventOrder', {}),
  17974. defaultedObjOf('model', {}, [
  17975. defaulted('getDisplayText', itemData => itemData.meta !== undefined && itemData.meta.text !== undefined ? itemData.meta.text : itemData.value),
  17976. defaulted('selectsOver', true),
  17977. defaulted('populateFromBrowse', true)
  17978. ]),
  17979. onHandler('onSetValue'),
  17980. onKeyboardHandler('onExecute'),
  17981. onHandler('onItemExecute'),
  17982. defaulted('inputClasses', []),
  17983. defaulted('inputAttributes', {}),
  17984. defaulted('inputStyles', {}),
  17985. defaulted('matchWidth', true),
  17986. defaulted('useMinWidth', false),
  17987. defaulted('dismissOnBlur', true),
  17988. markers$1(['openClass']),
  17989. option$3('initialData'),
  17990. field('typeaheadBehaviours', [
  17991. Focusing,
  17992. Representing,
  17993. Streaming,
  17994. Keying,
  17995. Toggling,
  17996. Coupling
  17997. ]),
  17998. customField('lazyTypeaheadComp', () => Cell(Optional.none)),
  17999. customField('previewing', () => Cell(true))
  18000. ].concat(schema$l()).concat(sandboxFields()));
  18001. const parts$b = constant$1([external({
  18002. schema: [tieredMenuMarkers()],
  18003. name: 'menu',
  18004. overrides: detail => {
  18005. return {
  18006. fakeFocus: true,
  18007. onHighlightItem: (_tmenu, menu, item) => {
  18008. if (!detail.previewing.get()) {
  18009. detail.lazyTypeaheadComp.get().each(input => {
  18010. if (detail.model.populateFromBrowse) {
  18011. setValueFromItem(detail.model, input, item);
  18012. }
  18013. getOpt(item.element, 'id').each(id => set$9(input.element, 'aria-activedescendant', id));
  18014. });
  18015. } else {
  18016. detail.lazyTypeaheadComp.get().each(input => {
  18017. attemptSelectOver(detail.model, input, item).fold(() => {
  18018. if (detail.model.selectsOver) {
  18019. Highlighting.dehighlight(menu, item);
  18020. detail.previewing.set(true);
  18021. } else {
  18022. detail.previewing.set(false);
  18023. }
  18024. }, selectOverTextInInput => {
  18025. selectOverTextInInput();
  18026. detail.previewing.set(false);
  18027. });
  18028. });
  18029. }
  18030. },
  18031. onExecute: (_menu, item) => {
  18032. return detail.lazyTypeaheadComp.get().map(typeahead => {
  18033. emitWith(typeahead, itemExecute(), { item });
  18034. return true;
  18035. });
  18036. },
  18037. onHover: (menu, item) => {
  18038. detail.previewing.set(false);
  18039. detail.lazyTypeaheadComp.get().each(input => {
  18040. if (detail.model.populateFromBrowse) {
  18041. setValueFromItem(detail.model, input, item);
  18042. }
  18043. });
  18044. }
  18045. };
  18046. }
  18047. })]);
  18048. const Typeahead = composite({
  18049. name: 'Typeahead',
  18050. configFields: schema$g(),
  18051. partFields: parts$b(),
  18052. factory: make$3
  18053. });
  18054. const wrap = delegate => {
  18055. const toCached = () => {
  18056. return wrap(delegate.toCached());
  18057. };
  18058. const bindFuture = f => {
  18059. return wrap(delegate.bind(resA => resA.fold(err => Future.pure(Result.error(err)), a => f(a))));
  18060. };
  18061. const bindResult = f => {
  18062. return wrap(delegate.map(resA => resA.bind(f)));
  18063. };
  18064. const mapResult = f => {
  18065. return wrap(delegate.map(resA => resA.map(f)));
  18066. };
  18067. const mapError = f => {
  18068. return wrap(delegate.map(resA => resA.mapError(f)));
  18069. };
  18070. const foldResult = (whenError, whenValue) => {
  18071. return delegate.map(res => res.fold(whenError, whenValue));
  18072. };
  18073. const withTimeout = (timeout, errorThunk) => {
  18074. return wrap(Future.nu(callback => {
  18075. let timedOut = false;
  18076. const timer = setTimeout(() => {
  18077. timedOut = true;
  18078. callback(Result.error(errorThunk()));
  18079. }, timeout);
  18080. delegate.get(result => {
  18081. if (!timedOut) {
  18082. clearTimeout(timer);
  18083. callback(result);
  18084. }
  18085. });
  18086. }));
  18087. };
  18088. return {
  18089. ...delegate,
  18090. toCached,
  18091. bindFuture,
  18092. bindResult,
  18093. mapResult,
  18094. mapError,
  18095. foldResult,
  18096. withTimeout
  18097. };
  18098. };
  18099. const nu$1 = worker => {
  18100. return wrap(Future.nu(worker));
  18101. };
  18102. const value = value => {
  18103. return wrap(Future.pure(Result.value(value)));
  18104. };
  18105. const error = error => {
  18106. return wrap(Future.pure(Result.error(error)));
  18107. };
  18108. const fromResult = result => {
  18109. return wrap(Future.pure(result));
  18110. };
  18111. const fromFuture = future => {
  18112. return wrap(future.map(Result.value));
  18113. };
  18114. const fromPromise = promise => {
  18115. return nu$1(completer => {
  18116. promise.then(value => {
  18117. completer(Result.value(value));
  18118. }, error => {
  18119. completer(Result.error(error));
  18120. });
  18121. });
  18122. };
  18123. const FutureResult = {
  18124. nu: nu$1,
  18125. wrap,
  18126. pure: value,
  18127. value,
  18128. error,
  18129. fromResult,
  18130. fromFuture,
  18131. fromPromise
  18132. };
  18133. const renderCommonSpec = (spec, actionOpt, extraBehaviours = [], dom, components, providersBackstage) => {
  18134. const action = actionOpt.fold(() => ({}), action => ({ action }));
  18135. const common = {
  18136. buttonBehaviours: derive$1([
  18137. DisablingConfigs.button(() => !spec.enabled || providersBackstage.isDisabled()),
  18138. receivingConfig(),
  18139. Tabstopping.config({}),
  18140. config('button press', [
  18141. preventDefault('click'),
  18142. preventDefault('mousedown')
  18143. ])
  18144. ].concat(extraBehaviours)),
  18145. eventOrder: {
  18146. click: [
  18147. 'button press',
  18148. 'alloy.base.behaviour'
  18149. ],
  18150. mousedown: [
  18151. 'button press',
  18152. 'alloy.base.behaviour'
  18153. ]
  18154. },
  18155. ...action
  18156. };
  18157. const domFinal = deepMerge(common, { dom });
  18158. return deepMerge(domFinal, { components });
  18159. };
  18160. const renderIconButtonSpec = (spec, action, providersBackstage, extraBehaviours = []) => {
  18161. const tooltipAttributes = spec.tooltip.map(tooltip => ({
  18162. 'aria-label': providersBackstage.translate(tooltip),
  18163. 'title': providersBackstage.translate(tooltip)
  18164. })).getOr({});
  18165. const dom = {
  18166. tag: 'button',
  18167. classes: ['tox-tbtn'],
  18168. attributes: tooltipAttributes
  18169. };
  18170. const icon = spec.icon.map(iconName => renderIconFromPack$1(iconName, providersBackstage.icons));
  18171. const components = componentRenderPipeline([icon]);
  18172. return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
  18173. };
  18174. const calculateClassesFromButtonType = buttonType => {
  18175. switch (buttonType) {
  18176. case 'primary':
  18177. return ['tox-button'];
  18178. case 'toolbar':
  18179. return ['tox-tbtn'];
  18180. case 'secondary':
  18181. default:
  18182. return [
  18183. 'tox-button',
  18184. 'tox-button--secondary'
  18185. ];
  18186. }
  18187. };
  18188. const renderButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
  18189. const translatedText = providersBackstage.translate(spec.text);
  18190. const icon = spec.icon.map(iconName => renderIconFromPack$1(iconName, providersBackstage.icons));
  18191. const components = [icon.getOrThunk(() => text$2(translatedText))];
  18192. const buttonType = spec.buttonType.getOr(!spec.primary && !spec.borderless ? 'secondary' : 'primary');
  18193. const baseClasses = calculateClassesFromButtonType(buttonType);
  18194. const classes = [
  18195. ...baseClasses,
  18196. ...icon.isSome() ? ['tox-button--icon'] : [],
  18197. ...spec.borderless ? ['tox-button--naked'] : [],
  18198. ...extraClasses
  18199. ];
  18200. const dom = {
  18201. tag: 'button',
  18202. classes,
  18203. attributes: { title: translatedText }
  18204. };
  18205. return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
  18206. };
  18207. const renderButton$1 = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
  18208. const buttonSpec = renderButtonSpec(spec, Optional.some(action), providersBackstage, extraBehaviours, extraClasses);
  18209. return Button.sketch(buttonSpec);
  18210. };
  18211. const getAction = (name, buttonType) => comp => {
  18212. if (buttonType === 'custom') {
  18213. emitWith(comp, formActionEvent, {
  18214. name,
  18215. value: {}
  18216. });
  18217. } else if (buttonType === 'submit') {
  18218. emit(comp, formSubmitEvent);
  18219. } else if (buttonType === 'cancel') {
  18220. emit(comp, formCancelEvent);
  18221. } else {
  18222. console.error('Unknown button type: ', buttonType);
  18223. }
  18224. };
  18225. const isMenuFooterButtonSpec = (spec, buttonType) => buttonType === 'menu';
  18226. const isNormalFooterButtonSpec = (spec, buttonType) => buttonType === 'custom' || buttonType === 'cancel' || buttonType === 'submit';
  18227. const isToggleButtonSpec = (spec, buttonType) => buttonType === 'togglebutton';
  18228. const renderToggleButton = (spec, providers) => {
  18229. var _a, _b;
  18230. const optMemIcon = spec.icon.map(memIcon => renderReplaceableIconFromPack(memIcon, providers.icons)).map(record);
  18231. const action = comp => {
  18232. emitWith(comp, formActionEvent, {
  18233. name: spec.name,
  18234. value: {
  18235. setIcon: newIcon => {
  18236. optMemIcon.map(memIcon => memIcon.getOpt(comp).each(displayIcon => {
  18237. Replacing.set(displayIcon, [renderReplaceableIconFromPack(newIcon, providers.icons)]);
  18238. }));
  18239. }
  18240. }
  18241. });
  18242. };
  18243. const buttonType = spec.buttonType.getOr(!spec.primary ? 'secondary' : 'primary');
  18244. const buttonSpec = {
  18245. ...spec,
  18246. name: (_a = spec.name) !== null && _a !== void 0 ? _a : '',
  18247. primary: buttonType === 'primary',
  18248. tooltip: Optional.from(spec.tooltip),
  18249. enabled: (_b = spec.enabled) !== null && _b !== void 0 ? _b : false,
  18250. borderless: false
  18251. };
  18252. const tooltipAttributes = buttonSpec.tooltip.map(tooltip => ({
  18253. 'aria-label': providers.translate(tooltip),
  18254. 'title': providers.translate(tooltip)
  18255. })).getOr({});
  18256. const buttonTypeClasses = calculateClassesFromButtonType(buttonType !== null && buttonType !== void 0 ? buttonType : 'secondary');
  18257. const showIconAndText = spec.icon.isSome() && spec.text.isSome();
  18258. const dom = {
  18259. tag: 'button',
  18260. classes: [
  18261. ...buttonTypeClasses.concat(spec.icon.isSome() ? ['tox-button--icon'] : []),
  18262. ...spec.active ? ['tox-button--enabled'] : [],
  18263. ...showIconAndText ? ['tox-button--icon-and-text'] : []
  18264. ],
  18265. attributes: tooltipAttributes
  18266. };
  18267. const extraBehaviours = [];
  18268. const translatedText = providers.translate(spec.text.getOr(''));
  18269. const translatedTextComponed = text$2(translatedText);
  18270. const iconComp = componentRenderPipeline([optMemIcon.map(memIcon => memIcon.asSpec())]);
  18271. const components = [
  18272. ...iconComp,
  18273. ...spec.text.isSome() ? [translatedTextComponed] : []
  18274. ];
  18275. const iconButtonSpec = renderCommonSpec(buttonSpec, Optional.some(action), extraBehaviours, dom, components, providers);
  18276. return Button.sketch(iconButtonSpec);
  18277. };
  18278. const renderFooterButton = (spec, buttonType, backstage) => {
  18279. if (isMenuFooterButtonSpec(spec, buttonType)) {
  18280. const getButton = () => memButton;
  18281. const menuButtonSpec = spec;
  18282. const fixedSpec = {
  18283. ...spec,
  18284. type: 'menubutton',
  18285. search: Optional.none(),
  18286. onSetup: api => {
  18287. api.setEnabled(spec.enabled);
  18288. return noop;
  18289. },
  18290. fetch: getFetch(menuButtonSpec.items, getButton, backstage)
  18291. };
  18292. const memButton = record(renderMenuButton(fixedSpec, 'tox-tbtn', backstage, Optional.none()));
  18293. return memButton.asSpec();
  18294. } else if (isNormalFooterButtonSpec(spec, buttonType)) {
  18295. const action = getAction(spec.name, buttonType);
  18296. const buttonSpec = {
  18297. ...spec,
  18298. borderless: false
  18299. };
  18300. return renderButton$1(buttonSpec, action, backstage.shared.providers, []);
  18301. } else if (isToggleButtonSpec(spec, buttonType)) {
  18302. return renderToggleButton(spec, backstage.shared.providers);
  18303. } else {
  18304. console.error('Unknown footer button type: ', buttonType);
  18305. throw new Error('Unknown footer button type');
  18306. }
  18307. };
  18308. const renderDialogButton = (spec, providersBackstage) => {
  18309. const action = getAction(spec.name, 'custom');
  18310. return renderFormField(Optional.none(), FormField.parts.field({
  18311. factory: Button,
  18312. ...renderButtonSpec(spec, Optional.some(action), providersBackstage, [
  18313. memory(''),
  18314. ComposingConfigs.self()
  18315. ])
  18316. }));
  18317. };
  18318. const separator$1 = { type: 'separator' };
  18319. const toMenuItem = target => ({
  18320. type: 'menuitem',
  18321. value: target.url,
  18322. text: target.title,
  18323. meta: { attach: target.attach },
  18324. onAction: noop
  18325. });
  18326. const staticMenuItem = (title, url) => ({
  18327. type: 'menuitem',
  18328. value: url,
  18329. text: title,
  18330. meta: { attach: undefined },
  18331. onAction: noop
  18332. });
  18333. const toMenuItems = targets => map$2(targets, toMenuItem);
  18334. const filterLinkTargets = (type, targets) => filter$2(targets, target => target.type === type);
  18335. const filteredTargets = (type, targets) => toMenuItems(filterLinkTargets(type, targets));
  18336. const headerTargets = linkInfo => filteredTargets('header', linkInfo.targets);
  18337. const anchorTargets = linkInfo => filteredTargets('anchor', linkInfo.targets);
  18338. const anchorTargetTop = linkInfo => Optional.from(linkInfo.anchorTop).map(url => staticMenuItem('<top>', url)).toArray();
  18339. const anchorTargetBottom = linkInfo => Optional.from(linkInfo.anchorBottom).map(url => staticMenuItem('<bottom>', url)).toArray();
  18340. const historyTargets = history => map$2(history, url => staticMenuItem(url, url));
  18341. const joinMenuLists = items => {
  18342. return foldl(items, (a, b) => {
  18343. const bothEmpty = a.length === 0 || b.length === 0;
  18344. return bothEmpty ? a.concat(b) : a.concat(separator$1, b);
  18345. }, []);
  18346. };
  18347. const filterByQuery = (term, menuItems) => {
  18348. const lowerCaseTerm = term.toLowerCase();
  18349. return filter$2(menuItems, item => {
  18350. var _a;
  18351. const text = item.meta !== undefined && item.meta.text !== undefined ? item.meta.text : item.text;
  18352. const value = (_a = item.value) !== null && _a !== void 0 ? _a : '';
  18353. return contains$1(text.toLowerCase(), lowerCaseTerm) || contains$1(value.toLowerCase(), lowerCaseTerm);
  18354. });
  18355. };
  18356. const getItems = (fileType, input, urlBackstage) => {
  18357. var _a, _b;
  18358. const urlInputValue = Representing.getValue(input);
  18359. const term = (_b = (_a = urlInputValue === null || urlInputValue === void 0 ? void 0 : urlInputValue.meta) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : urlInputValue.value;
  18360. const info = urlBackstage.getLinkInformation();
  18361. return info.fold(() => [], linkInfo => {
  18362. const history = filterByQuery(term, historyTargets(urlBackstage.getHistory(fileType)));
  18363. return fileType === 'file' ? joinMenuLists([
  18364. history,
  18365. filterByQuery(term, headerTargets(linkInfo)),
  18366. filterByQuery(term, flatten([
  18367. anchorTargetTop(linkInfo),
  18368. anchorTargets(linkInfo),
  18369. anchorTargetBottom(linkInfo)
  18370. ]))
  18371. ]) : history;
  18372. });
  18373. };
  18374. const errorId = generate$6('aria-invalid');
  18375. const renderUrlInput = (spec, backstage, urlBackstage, initialData) => {
  18376. const providersBackstage = backstage.shared.providers;
  18377. const updateHistory = component => {
  18378. const urlEntry = Representing.getValue(component);
  18379. urlBackstage.addToHistory(urlEntry.value, spec.filetype);
  18380. };
  18381. const typeaheadSpec = {
  18382. ...initialData.map(initialData => ({ initialData })).getOr({}),
  18383. dismissOnBlur: true,
  18384. inputClasses: ['tox-textfield'],
  18385. sandboxClasses: ['tox-dialog__popups'],
  18386. inputAttributes: {
  18387. 'aria-errormessage': errorId,
  18388. 'type': 'url'
  18389. },
  18390. minChars: 0,
  18391. responseTime: 0,
  18392. fetch: input => {
  18393. const items = getItems(spec.filetype, input, urlBackstage);
  18394. const tdata = build(items, ItemResponse$1.BUBBLE_TO_SANDBOX, backstage, {
  18395. isHorizontalMenu: false,
  18396. search: Optional.none()
  18397. });
  18398. return Future.pure(tdata);
  18399. },
  18400. getHotspot: comp => memUrlBox.getOpt(comp),
  18401. onSetValue: (comp, _newValue) => {
  18402. if (comp.hasConfigured(Invalidating)) {
  18403. Invalidating.run(comp).get(noop);
  18404. }
  18405. },
  18406. typeaheadBehaviours: derive$1([
  18407. ...urlBackstage.getValidationHandler().map(handler => Invalidating.config({
  18408. getRoot: comp => parentElement(comp.element),
  18409. invalidClass: 'tox-control-wrap--status-invalid',
  18410. notify: {
  18411. onInvalid: (comp, err) => {
  18412. memInvalidIcon.getOpt(comp).each(invalidComp => {
  18413. set$9(invalidComp.element, 'title', providersBackstage.translate(err));
  18414. });
  18415. }
  18416. },
  18417. validator: {
  18418. validate: input => {
  18419. const urlEntry = Representing.getValue(input);
  18420. return FutureResult.nu(completer => {
  18421. handler({
  18422. type: spec.filetype,
  18423. url: urlEntry.value
  18424. }, validation => {
  18425. if (validation.status === 'invalid') {
  18426. const err = Result.error(validation.message);
  18427. completer(err);
  18428. } else {
  18429. const val = Result.value(validation.message);
  18430. completer(val);
  18431. }
  18432. });
  18433. });
  18434. },
  18435. validateOnLoad: false
  18436. }
  18437. })).toArray(),
  18438. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  18439. Tabstopping.config({}),
  18440. config('urlinput-events', [
  18441. run$1(input(), comp => {
  18442. const currentValue = get$6(comp.element);
  18443. const trimmedValue = currentValue.trim();
  18444. if (trimmedValue !== currentValue) {
  18445. set$5(comp.element, trimmedValue);
  18446. }
  18447. if (spec.filetype === 'file') {
  18448. emitWith(comp, formChangeEvent, { name: spec.name });
  18449. }
  18450. }),
  18451. run$1(change(), comp => {
  18452. emitWith(comp, formChangeEvent, { name: spec.name });
  18453. updateHistory(comp);
  18454. }),
  18455. run$1(postPaste(), comp => {
  18456. emitWith(comp, formChangeEvent, { name: spec.name });
  18457. updateHistory(comp);
  18458. })
  18459. ])
  18460. ]),
  18461. eventOrder: {
  18462. [input()]: [
  18463. 'streaming',
  18464. 'urlinput-events',
  18465. 'invalidating'
  18466. ]
  18467. },
  18468. model: {
  18469. getDisplayText: itemData => itemData.value,
  18470. selectsOver: false,
  18471. populateFromBrowse: false
  18472. },
  18473. markers: { openClass: 'tox-textfield--popup-open' },
  18474. lazySink: backstage.shared.getSink,
  18475. parts: { menu: part(false, 1, 'normal') },
  18476. onExecute: (_menu, component, _entry) => {
  18477. emitWith(component, formSubmitEvent, {});
  18478. },
  18479. onItemExecute: (typeahead, _sandbox, _item, _value) => {
  18480. updateHistory(typeahead);
  18481. emitWith(typeahead, formChangeEvent, { name: spec.name });
  18482. }
  18483. };
  18484. const pField = FormField.parts.field({
  18485. ...typeaheadSpec,
  18486. factory: Typeahead
  18487. });
  18488. const pLabel = spec.label.map(label => renderLabel$3(label, providersBackstage));
  18489. const makeIcon = (name, errId, icon = name, label = name) => render$3(icon, {
  18490. tag: 'div',
  18491. classes: [
  18492. 'tox-icon',
  18493. 'tox-control-wrap__status-icon-' + name
  18494. ],
  18495. attributes: {
  18496. 'title': providersBackstage.translate(label),
  18497. 'aria-live': 'polite',
  18498. ...errId.fold(() => ({}), id => ({ id }))
  18499. }
  18500. }, providersBackstage.icons);
  18501. const memInvalidIcon = record(makeIcon('invalid', Optional.some(errorId), 'warning'));
  18502. const memStatus = record({
  18503. dom: {
  18504. tag: 'div',
  18505. classes: ['tox-control-wrap__status-icon-wrap']
  18506. },
  18507. components: [memInvalidIcon.asSpec()]
  18508. });
  18509. const optUrlPicker = urlBackstage.getUrlPicker(spec.filetype);
  18510. const browseUrlEvent = generate$6('browser.url.event');
  18511. const memUrlBox = record({
  18512. dom: {
  18513. tag: 'div',
  18514. classes: ['tox-control-wrap']
  18515. },
  18516. components: [
  18517. pField,
  18518. memStatus.asSpec()
  18519. ],
  18520. behaviours: derive$1([Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() })])
  18521. });
  18522. const memUrlPickerButton = record(renderButton$1({
  18523. name: spec.name,
  18524. icon: Optional.some('browse'),
  18525. text: spec.picker_text.or(spec.label).getOr(''),
  18526. enabled: spec.enabled,
  18527. primary: false,
  18528. buttonType: Optional.none(),
  18529. borderless: true
  18530. }, component => emit(component, browseUrlEvent), providersBackstage, [], ['tox-browse-url']));
  18531. const controlHWrapper = () => ({
  18532. dom: {
  18533. tag: 'div',
  18534. classes: ['tox-form__controls-h-stack']
  18535. },
  18536. components: flatten([
  18537. [memUrlBox.asSpec()],
  18538. optUrlPicker.map(() => memUrlPickerButton.asSpec()).toArray()
  18539. ])
  18540. });
  18541. const openUrlPicker = comp => {
  18542. Composing.getCurrent(comp).each(field => {
  18543. const componentData = Representing.getValue(field);
  18544. const urlData = {
  18545. fieldname: spec.name,
  18546. ...componentData
  18547. };
  18548. optUrlPicker.each(picker => {
  18549. picker(urlData).get(chosenData => {
  18550. Representing.setValue(field, chosenData);
  18551. emitWith(comp, formChangeEvent, { name: spec.name });
  18552. });
  18553. });
  18554. });
  18555. };
  18556. return FormField.sketch({
  18557. dom: renderFormFieldDom(),
  18558. components: pLabel.toArray().concat([controlHWrapper()]),
  18559. fieldBehaviours: derive$1([
  18560. Disabling.config({
  18561. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  18562. onDisabled: comp => {
  18563. FormField.getField(comp).each(Disabling.disable);
  18564. memUrlPickerButton.getOpt(comp).each(Disabling.disable);
  18565. },
  18566. onEnabled: comp => {
  18567. FormField.getField(comp).each(Disabling.enable);
  18568. memUrlPickerButton.getOpt(comp).each(Disabling.enable);
  18569. }
  18570. }),
  18571. receivingConfig(),
  18572. config('url-input-events', [run$1(browseUrlEvent, openUrlPicker)])
  18573. ])
  18574. });
  18575. };
  18576. const renderAlertBanner = (spec, providersBackstage) => {
  18577. const icon = get$2(spec.icon, providersBackstage.icons);
  18578. return Container.sketch({
  18579. dom: {
  18580. tag: 'div',
  18581. attributes: { role: 'alert' },
  18582. classes: [
  18583. 'tox-notification',
  18584. 'tox-notification--in',
  18585. `tox-notification--${ spec.level }`
  18586. ]
  18587. },
  18588. components: [
  18589. {
  18590. dom: {
  18591. tag: 'div',
  18592. classes: ['tox-notification__icon'],
  18593. innerHtml: !spec.url ? icon : undefined
  18594. },
  18595. components: spec.url ? [Button.sketch({
  18596. dom: {
  18597. tag: 'button',
  18598. classes: [
  18599. 'tox-button',
  18600. 'tox-button--naked',
  18601. 'tox-button--icon'
  18602. ],
  18603. innerHtml: icon,
  18604. attributes: { title: providersBackstage.translate(spec.iconTooltip) }
  18605. },
  18606. action: comp => emitWith(comp, formActionEvent, {
  18607. name: 'alert-banner',
  18608. value: spec.url
  18609. }),
  18610. buttonBehaviours: derive$1([addFocusableBehaviour()])
  18611. })] : undefined
  18612. },
  18613. {
  18614. dom: {
  18615. tag: 'div',
  18616. classes: ['tox-notification__body'],
  18617. innerHtml: providersBackstage.translate(spec.text)
  18618. }
  18619. }
  18620. ]
  18621. });
  18622. };
  18623. const set$1 = (element, status) => {
  18624. element.dom.checked = status;
  18625. };
  18626. const get$1 = element => element.dom.checked;
  18627. const renderCheckbox = (spec, providerBackstage, initialData) => {
  18628. const toggleCheckboxHandler = comp => {
  18629. comp.element.dom.click();
  18630. return Optional.some(true);
  18631. };
  18632. const pField = FormField.parts.field({
  18633. factory: { sketch: identity },
  18634. dom: {
  18635. tag: 'input',
  18636. classes: ['tox-checkbox__input'],
  18637. attributes: { type: 'checkbox' }
  18638. },
  18639. behaviours: derive$1([
  18640. ComposingConfigs.self(),
  18641. Disabling.config({
  18642. disabled: () => !spec.enabled || providerBackstage.isDisabled(),
  18643. onDisabled: component => {
  18644. parentElement(component.element).each(element => add$2(element, 'tox-checkbox--disabled'));
  18645. },
  18646. onEnabled: component => {
  18647. parentElement(component.element).each(element => remove$2(element, 'tox-checkbox--disabled'));
  18648. }
  18649. }),
  18650. Tabstopping.config({}),
  18651. Focusing.config({}),
  18652. withElement(initialData, get$1, set$1),
  18653. Keying.config({
  18654. mode: 'special',
  18655. onEnter: toggleCheckboxHandler,
  18656. onSpace: toggleCheckboxHandler,
  18657. stopSpaceKeyup: true
  18658. }),
  18659. config('checkbox-events', [run$1(change(), (component, _) => {
  18660. emitWith(component, formChangeEvent, { name: spec.name });
  18661. })])
  18662. ])
  18663. });
  18664. const pLabel = FormField.parts.label({
  18665. dom: {
  18666. tag: 'span',
  18667. classes: ['tox-checkbox__label']
  18668. },
  18669. components: [text$2(providerBackstage.translate(spec.label))],
  18670. behaviours: derive$1([Unselecting.config({})])
  18671. });
  18672. const makeIcon = className => {
  18673. const iconName = className === 'checked' ? 'selected' : 'unselected';
  18674. return render$3(iconName, {
  18675. tag: 'span',
  18676. classes: [
  18677. 'tox-icon',
  18678. 'tox-checkbox-icon__' + className
  18679. ]
  18680. }, providerBackstage.icons);
  18681. };
  18682. const memIcons = record({
  18683. dom: {
  18684. tag: 'div',
  18685. classes: ['tox-checkbox__icons']
  18686. },
  18687. components: [
  18688. makeIcon('checked'),
  18689. makeIcon('unchecked')
  18690. ]
  18691. });
  18692. return FormField.sketch({
  18693. dom: {
  18694. tag: 'label',
  18695. classes: ['tox-checkbox']
  18696. },
  18697. components: [
  18698. pField,
  18699. memIcons.asSpec(),
  18700. pLabel
  18701. ],
  18702. fieldBehaviours: derive$1([
  18703. Disabling.config({ disabled: () => !spec.enabled || providerBackstage.isDisabled() }),
  18704. receivingConfig()
  18705. ])
  18706. });
  18707. };
  18708. const renderHtmlPanel = spec => {
  18709. if (spec.presets === 'presentation') {
  18710. return Container.sketch({
  18711. dom: {
  18712. tag: 'div',
  18713. classes: ['tox-form__group'],
  18714. innerHtml: spec.html
  18715. }
  18716. });
  18717. } else {
  18718. return Container.sketch({
  18719. dom: {
  18720. tag: 'div',
  18721. classes: ['tox-form__group'],
  18722. innerHtml: spec.html,
  18723. attributes: { role: 'document' }
  18724. },
  18725. containerBehaviours: derive$1([
  18726. Tabstopping.config({}),
  18727. Focusing.config({})
  18728. ])
  18729. });
  18730. }
  18731. };
  18732. const make$2 = render => {
  18733. return (parts, spec, dialogData, backstage) => get$g(spec, 'name').fold(() => render(spec, backstage, Optional.none()), fieldName => parts.field(fieldName, render(spec, backstage, get$g(dialogData, fieldName))));
  18734. };
  18735. const makeIframe = render => (parts, spec, dialogData, backstage) => {
  18736. const iframeSpec = deepMerge(spec, { source: 'dynamic' });
  18737. return make$2(render)(parts, iframeSpec, dialogData, backstage);
  18738. };
  18739. const factories = {
  18740. bar: make$2((spec, backstage) => renderBar(spec, backstage.shared)),
  18741. collection: make$2((spec, backstage, data) => renderCollection(spec, backstage.shared.providers, data)),
  18742. alertbanner: make$2((spec, backstage) => renderAlertBanner(spec, backstage.shared.providers)),
  18743. input: make$2((spec, backstage, data) => renderInput(spec, backstage.shared.providers, data)),
  18744. textarea: make$2((spec, backstage, data) => renderTextarea(spec, backstage.shared.providers, data)),
  18745. label: make$2((spec, backstage) => renderLabel$2(spec, backstage.shared)),
  18746. iframe: makeIframe((spec, backstage, data) => renderIFrame(spec, backstage.shared.providers, data)),
  18747. button: make$2((spec, backstage) => renderDialogButton(spec, backstage.shared.providers)),
  18748. checkbox: make$2((spec, backstage, data) => renderCheckbox(spec, backstage.shared.providers, data)),
  18749. colorinput: make$2((spec, backstage, data) => renderColorInput(spec, backstage.shared, backstage.colorinput, data)),
  18750. colorpicker: make$2((spec, backstage, data) => renderColorPicker(spec, backstage.shared.providers, data)),
  18751. dropzone: make$2((spec, backstage, data) => renderDropZone(spec, backstage.shared.providers, data)),
  18752. grid: make$2((spec, backstage) => renderGrid(spec, backstage.shared)),
  18753. listbox: make$2((spec, backstage, data) => renderListBox(spec, backstage, data)),
  18754. selectbox: make$2((spec, backstage, data) => renderSelectBox(spec, backstage.shared.providers, data)),
  18755. sizeinput: make$2((spec, backstage) => renderSizeInput(spec, backstage.shared.providers)),
  18756. slider: make$2((spec, backstage, data) => renderSlider(spec, backstage.shared.providers, data)),
  18757. urlinput: make$2((spec, backstage, data) => renderUrlInput(spec, backstage, backstage.urlinput, data)),
  18758. customeditor: make$2(renderCustomEditor),
  18759. htmlpanel: make$2(renderHtmlPanel),
  18760. imagepreview: make$2((spec, _, data) => renderImagePreview(spec, data)),
  18761. table: make$2((spec, backstage) => renderTable(spec, backstage.shared.providers)),
  18762. tree: make$2((spec, backstage) => renderTree(spec, backstage)),
  18763. panel: make$2((spec, backstage) => renderPanel(spec, backstage))
  18764. };
  18765. const noFormParts = {
  18766. field: (_name, spec) => spec,
  18767. record: constant$1([])
  18768. };
  18769. const interpretInForm = (parts, spec, dialogData, oldBackstage) => {
  18770. const newBackstage = deepMerge(oldBackstage, { shared: { interpreter: childSpec => interpretParts(parts, childSpec, dialogData, newBackstage) } });
  18771. return interpretParts(parts, spec, dialogData, newBackstage);
  18772. };
  18773. const interpretParts = (parts, spec, dialogData, backstage) => get$g(factories, spec.type).fold(() => {
  18774. console.error(`Unknown factory type "${ spec.type }", defaulting to container: `, spec);
  18775. return spec;
  18776. }, factory => factory(parts, spec, dialogData, backstage));
  18777. const interpretWithoutForm = (spec, dialogData, backstage) => interpretParts(noFormParts, spec, dialogData, backstage);
  18778. const labelPrefix = 'layout-inset';
  18779. const westEdgeX = anchor => anchor.x;
  18780. const middleX = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
  18781. const eastEdgeX = (anchor, element) => anchor.x + anchor.width - element.width;
  18782. const northY = anchor => anchor.y;
  18783. const southY = (anchor, element) => anchor.y + anchor.height - element.height;
  18784. const centreY = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
  18785. const southwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), southY(anchor, element), bubbles.insetSouthwest(), northwest$3(), 'southwest', boundsRestriction(anchor, {
  18786. right: 0,
  18787. bottom: 3
  18788. }), labelPrefix);
  18789. const southeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), southY(anchor, element), bubbles.insetSoutheast(), northeast$3(), 'southeast', boundsRestriction(anchor, {
  18790. left: 1,
  18791. bottom: 3
  18792. }), labelPrefix);
  18793. const northwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), northY(anchor), bubbles.insetNorthwest(), southwest$3(), 'northwest', boundsRestriction(anchor, {
  18794. right: 0,
  18795. top: 2
  18796. }), labelPrefix);
  18797. const northeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), northY(anchor), bubbles.insetNortheast(), southeast$3(), 'northeast', boundsRestriction(anchor, {
  18798. left: 1,
  18799. top: 2
  18800. }), labelPrefix);
  18801. const north = (anchor, element, bubbles) => nu$6(middleX(anchor, element), northY(anchor), bubbles.insetNorth(), south$3(), 'north', boundsRestriction(anchor, { top: 2 }), labelPrefix);
  18802. const south = (anchor, element, bubbles) => nu$6(middleX(anchor, element), southY(anchor, element), bubbles.insetSouth(), north$3(), 'south', boundsRestriction(anchor, { bottom: 3 }), labelPrefix);
  18803. const east = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), centreY(anchor, element), bubbles.insetEast(), west$3(), 'east', boundsRestriction(anchor, { right: 0 }), labelPrefix);
  18804. const west = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), centreY(anchor, element), bubbles.insetWest(), east$3(), 'west', boundsRestriction(anchor, { left: 1 }), labelPrefix);
  18805. const lookupPreserveLayout = lastPlacement => {
  18806. switch (lastPlacement) {
  18807. case 'north':
  18808. return north;
  18809. case 'northeast':
  18810. return northeast;
  18811. case 'northwest':
  18812. return northwest;
  18813. case 'south':
  18814. return south;
  18815. case 'southeast':
  18816. return southeast;
  18817. case 'southwest':
  18818. return southwest;
  18819. case 'east':
  18820. return east;
  18821. case 'west':
  18822. return west;
  18823. }
  18824. };
  18825. const preserve = (anchor, element, bubbles, placee, bounds) => {
  18826. const layout = getPlacement(placee).map(lookupPreserveLayout).getOr(north);
  18827. return layout(anchor, element, bubbles, placee, bounds);
  18828. };
  18829. const lookupFlippedLayout = lastPlacement => {
  18830. switch (lastPlacement) {
  18831. case 'north':
  18832. return south;
  18833. case 'northeast':
  18834. return southeast;
  18835. case 'northwest':
  18836. return southwest;
  18837. case 'south':
  18838. return north;
  18839. case 'southeast':
  18840. return northeast;
  18841. case 'southwest':
  18842. return northwest;
  18843. case 'east':
  18844. return west;
  18845. case 'west':
  18846. return east;
  18847. }
  18848. };
  18849. const flip = (anchor, element, bubbles, placee, bounds) => {
  18850. const layout = getPlacement(placee).map(lookupFlippedLayout).getOr(north);
  18851. return layout(anchor, element, bubbles, placee, bounds);
  18852. };
  18853. const bubbleAlignments$2 = {
  18854. valignCentre: [],
  18855. alignCentre: [],
  18856. alignLeft: [],
  18857. alignRight: [],
  18858. right: [],
  18859. left: [],
  18860. bottom: [],
  18861. top: []
  18862. };
  18863. const getInlineDialogAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
  18864. const bubbleSize = 12;
  18865. const overrides = { maxHeightFunction: expandable$1() };
  18866. const editableAreaAnchor = () => ({
  18867. type: 'node',
  18868. root: getContentContainer(getRootNode(contentAreaElement())),
  18869. node: Optional.from(contentAreaElement()),
  18870. bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
  18871. layouts: {
  18872. onRtl: () => [northeast],
  18873. onLtr: () => [northwest]
  18874. },
  18875. overrides
  18876. });
  18877. const standardAnchor = () => ({
  18878. type: 'hotspot',
  18879. hotspot: lazyAnchorbar(),
  18880. bubble: nu$5(-bubbleSize, bubbleSize, bubbleAlignments$2),
  18881. layouts: {
  18882. onRtl: () => [
  18883. southeast$2,
  18884. southwest$2,
  18885. south$2
  18886. ],
  18887. onLtr: () => [
  18888. southwest$2,
  18889. southeast$2,
  18890. south$2
  18891. ]
  18892. },
  18893. overrides
  18894. });
  18895. return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  18896. };
  18897. const getInlineBottomDialogAnchor = (inline, contentAreaElement, lazyBottomAnchorBar, lazyUseEditableAreaAnchor) => {
  18898. const bubbleSize = 12;
  18899. const overrides = { maxHeightFunction: expandable$1() };
  18900. const editableAreaAnchor = () => ({
  18901. type: 'node',
  18902. root: getContentContainer(getRootNode(contentAreaElement())),
  18903. node: Optional.from(contentAreaElement()),
  18904. bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
  18905. layouts: {
  18906. onRtl: () => [north],
  18907. onLtr: () => [north]
  18908. },
  18909. overrides
  18910. });
  18911. const standardAnchor = () => inline ? {
  18912. type: 'node',
  18913. root: getContentContainer(getRootNode(contentAreaElement())),
  18914. node: Optional.from(contentAreaElement()),
  18915. bubble: nu$5(0, -getOuter$2(contentAreaElement()), bubbleAlignments$2),
  18916. layouts: {
  18917. onRtl: () => [north$2],
  18918. onLtr: () => [north$2]
  18919. },
  18920. overrides
  18921. } : {
  18922. type: 'hotspot',
  18923. hotspot: lazyBottomAnchorBar(),
  18924. bubble: nu$5(0, 0, bubbleAlignments$2),
  18925. layouts: {
  18926. onRtl: () => [north$2],
  18927. onLtr: () => [north$2]
  18928. },
  18929. overrides
  18930. };
  18931. return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  18932. };
  18933. const getBannerAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
  18934. const editableAreaAnchor = () => ({
  18935. type: 'node',
  18936. root: getContentContainer(getRootNode(contentAreaElement())),
  18937. node: Optional.from(contentAreaElement()),
  18938. layouts: {
  18939. onRtl: () => [north],
  18940. onLtr: () => [north]
  18941. }
  18942. });
  18943. const standardAnchor = () => ({
  18944. type: 'hotspot',
  18945. hotspot: lazyAnchorbar(),
  18946. layouts: {
  18947. onRtl: () => [south$2],
  18948. onLtr: () => [south$2]
  18949. }
  18950. });
  18951. return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  18952. };
  18953. const getCursorAnchor = (editor, bodyElement) => () => ({
  18954. type: 'selection',
  18955. root: bodyElement(),
  18956. getSelection: () => {
  18957. const rng = editor.selection.getRng();
  18958. const selectedCells = editor.model.table.getSelectedCells();
  18959. if (selectedCells.length > 1) {
  18960. const firstCell = selectedCells[0];
  18961. const lastCell = selectedCells[selectedCells.length - 1];
  18962. const selectionTableCellRange = {
  18963. firstCell: SugarElement.fromDom(firstCell),
  18964. lastCell: SugarElement.fromDom(lastCell)
  18965. };
  18966. return Optional.some(selectionTableCellRange);
  18967. }
  18968. return Optional.some(SimSelection.range(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
  18969. }
  18970. });
  18971. const getNodeAnchor$1 = bodyElement => element => ({
  18972. type: 'node',
  18973. root: bodyElement(),
  18974. node: element
  18975. });
  18976. const getAnchors = (editor, lazyAnchorbar, lazyBottomAnchorBar, isToolbarTop) => {
  18977. const useFixedToolbarContainer = useFixedContainer(editor);
  18978. const bodyElement = () => SugarElement.fromDom(editor.getBody());
  18979. const contentAreaElement = () => SugarElement.fromDom(editor.getContentAreaContainer());
  18980. const lazyUseEditableAreaAnchor = () => useFixedToolbarContainer || !isToolbarTop();
  18981. return {
  18982. inlineDialog: getInlineDialogAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
  18983. inlineBottomDialog: getInlineBottomDialogAnchor(editor.inline, contentAreaElement, lazyBottomAnchorBar, lazyUseEditableAreaAnchor),
  18984. banner: getBannerAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
  18985. cursor: getCursorAnchor(editor, bodyElement),
  18986. node: getNodeAnchor$1(bodyElement)
  18987. };
  18988. };
  18989. const colorPicker = editor => (callback, value) => {
  18990. const dialog = colorPickerDialog(editor);
  18991. dialog(callback, value);
  18992. };
  18993. const hasCustomColors = editor => () => hasCustomColors$1(editor);
  18994. const getColors = editor => id => getColors$2(editor, id);
  18995. const getColorCols = editor => id => getColorCols$1(editor, id);
  18996. const ColorInputBackstage = editor => ({
  18997. colorPicker: colorPicker(editor),
  18998. hasCustomColors: hasCustomColors(editor),
  18999. getColors: getColors(editor),
  19000. getColorCols: getColorCols(editor)
  19001. });
  19002. const isDraggableModal = editor => () => isDraggableModal$1(editor);
  19003. const DialogBackstage = editor => ({ isDraggableModal: isDraggableModal(editor) });
  19004. const HeaderBackstage = editor => {
  19005. const mode = Cell(isToolbarLocationBottom(editor) ? 'bottom' : 'top');
  19006. return {
  19007. isPositionedAtTop: () => mode.get() === 'top',
  19008. getDockingMode: mode.get,
  19009. setDockingMode: mode.set
  19010. };
  19011. };
  19012. const isNestedFormat = format => hasNonNullableKey(format, 'items');
  19013. const isFormatReference = format => hasNonNullableKey(format, 'format');
  19014. const defaultStyleFormats = [
  19015. {
  19016. title: 'Headings',
  19017. items: [
  19018. {
  19019. title: 'Heading 1',
  19020. format: 'h1'
  19021. },
  19022. {
  19023. title: 'Heading 2',
  19024. format: 'h2'
  19025. },
  19026. {
  19027. title: 'Heading 3',
  19028. format: 'h3'
  19029. },
  19030. {
  19031. title: 'Heading 4',
  19032. format: 'h4'
  19033. },
  19034. {
  19035. title: 'Heading 5',
  19036. format: 'h5'
  19037. },
  19038. {
  19039. title: 'Heading 6',
  19040. format: 'h6'
  19041. }
  19042. ]
  19043. },
  19044. {
  19045. title: 'Inline',
  19046. items: [
  19047. {
  19048. title: 'Bold',
  19049. format: 'bold'
  19050. },
  19051. {
  19052. title: 'Italic',
  19053. format: 'italic'
  19054. },
  19055. {
  19056. title: 'Underline',
  19057. format: 'underline'
  19058. },
  19059. {
  19060. title: 'Strikethrough',
  19061. format: 'strikethrough'
  19062. },
  19063. {
  19064. title: 'Superscript',
  19065. format: 'superscript'
  19066. },
  19067. {
  19068. title: 'Subscript',
  19069. format: 'subscript'
  19070. },
  19071. {
  19072. title: 'Code',
  19073. format: 'code'
  19074. }
  19075. ]
  19076. },
  19077. {
  19078. title: 'Blocks',
  19079. items: [
  19080. {
  19081. title: 'Paragraph',
  19082. format: 'p'
  19083. },
  19084. {
  19085. title: 'Blockquote',
  19086. format: 'blockquote'
  19087. },
  19088. {
  19089. title: 'Div',
  19090. format: 'div'
  19091. },
  19092. {
  19093. title: 'Pre',
  19094. format: 'pre'
  19095. }
  19096. ]
  19097. },
  19098. {
  19099. title: 'Align',
  19100. items: [
  19101. {
  19102. title: 'Left',
  19103. format: 'alignleft'
  19104. },
  19105. {
  19106. title: 'Center',
  19107. format: 'aligncenter'
  19108. },
  19109. {
  19110. title: 'Right',
  19111. format: 'alignright'
  19112. },
  19113. {
  19114. title: 'Justify',
  19115. format: 'alignjustify'
  19116. }
  19117. ]
  19118. }
  19119. ];
  19120. const isNestedFormats = format => has$2(format, 'items');
  19121. const isBlockFormat = format => has$2(format, 'block');
  19122. const isInlineFormat = format => has$2(format, 'inline');
  19123. const isSelectorFormat = format => has$2(format, 'selector');
  19124. const mapFormats = userFormats => foldl(userFormats, (acc, fmt) => {
  19125. if (isNestedFormats(fmt)) {
  19126. const result = mapFormats(fmt.items);
  19127. return {
  19128. customFormats: acc.customFormats.concat(result.customFormats),
  19129. formats: acc.formats.concat([{
  19130. title: fmt.title,
  19131. items: result.formats
  19132. }])
  19133. };
  19134. } else if (isInlineFormat(fmt) || isBlockFormat(fmt) || isSelectorFormat(fmt)) {
  19135. const formatName = isString(fmt.name) ? fmt.name : fmt.title.toLowerCase();
  19136. const formatNameWithPrefix = `custom-${ formatName }`;
  19137. return {
  19138. customFormats: acc.customFormats.concat([{
  19139. name: formatNameWithPrefix,
  19140. format: fmt
  19141. }]),
  19142. formats: acc.formats.concat([{
  19143. title: fmt.title,
  19144. format: formatNameWithPrefix,
  19145. icon: fmt.icon
  19146. }])
  19147. };
  19148. } else {
  19149. return {
  19150. ...acc,
  19151. formats: acc.formats.concat(fmt)
  19152. };
  19153. }
  19154. }, {
  19155. customFormats: [],
  19156. formats: []
  19157. });
  19158. const registerCustomFormats = (editor, userFormats) => {
  19159. const result = mapFormats(userFormats);
  19160. const registerFormats = customFormats => {
  19161. each$1(customFormats, fmt => {
  19162. if (!editor.formatter.has(fmt.name)) {
  19163. editor.formatter.register(fmt.name, fmt.format);
  19164. }
  19165. });
  19166. };
  19167. if (editor.formatter) {
  19168. registerFormats(result.customFormats);
  19169. } else {
  19170. editor.on('init', () => {
  19171. registerFormats(result.customFormats);
  19172. });
  19173. }
  19174. return result.formats;
  19175. };
  19176. const getStyleFormats = editor => getUserStyleFormats(editor).map(userFormats => {
  19177. const registeredUserFormats = registerCustomFormats(editor, userFormats);
  19178. return shouldMergeStyleFormats(editor) ? defaultStyleFormats.concat(registeredUserFormats) : registeredUserFormats;
  19179. }).getOr(defaultStyleFormats);
  19180. const isSeparator$1 = format => {
  19181. const keys$1 = keys(format);
  19182. return keys$1.length === 1 && contains$2(keys$1, 'title');
  19183. };
  19184. const processBasic = (item, isSelectedFor, getPreviewFor) => ({
  19185. ...item,
  19186. type: 'formatter',
  19187. isSelected: isSelectedFor(item.format),
  19188. getStylePreview: getPreviewFor(item.format)
  19189. });
  19190. const register$a = (editor, formats, isSelectedFor, getPreviewFor) => {
  19191. const enrichSupported = item => processBasic(item, isSelectedFor, getPreviewFor);
  19192. const enrichMenu = item => {
  19193. const newItems = doEnrich(item.items);
  19194. return {
  19195. ...item,
  19196. type: 'submenu',
  19197. getStyleItems: constant$1(newItems)
  19198. };
  19199. };
  19200. const enrichCustom = item => {
  19201. const formatName = isString(item.name) ? item.name : generate$6(item.title);
  19202. const formatNameWithPrefix = `custom-${ formatName }`;
  19203. const newItem = {
  19204. ...item,
  19205. type: 'formatter',
  19206. format: formatNameWithPrefix,
  19207. isSelected: isSelectedFor(formatNameWithPrefix),
  19208. getStylePreview: getPreviewFor(formatNameWithPrefix)
  19209. };
  19210. editor.formatter.register(formatName, newItem);
  19211. return newItem;
  19212. };
  19213. const doEnrich = items => map$2(items, item => {
  19214. if (isNestedFormat(item)) {
  19215. return enrichMenu(item);
  19216. } else if (isFormatReference(item)) {
  19217. return enrichSupported(item);
  19218. } else if (isSeparator$1(item)) {
  19219. return {
  19220. ...item,
  19221. type: 'separator'
  19222. };
  19223. } else {
  19224. return enrichCustom(item);
  19225. }
  19226. });
  19227. return doEnrich(formats);
  19228. };
  19229. const init$7 = editor => {
  19230. const isSelectedFor = format => () => editor.formatter.match(format);
  19231. const getPreviewFor = format => () => {
  19232. const fmt = editor.formatter.get(format);
  19233. return fmt !== undefined ? Optional.some({
  19234. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  19235. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  19236. }) : Optional.none();
  19237. };
  19238. const settingsFormats = Cell([]);
  19239. const eventsFormats = Cell([]);
  19240. const replaceSettings = Cell(false);
  19241. editor.on('PreInit', _e => {
  19242. const formats = getStyleFormats(editor);
  19243. const enriched = register$a(editor, formats, isSelectedFor, getPreviewFor);
  19244. settingsFormats.set(enriched);
  19245. });
  19246. editor.on('addStyleModifications', e => {
  19247. const modifications = register$a(editor, e.items, isSelectedFor, getPreviewFor);
  19248. eventsFormats.set(modifications);
  19249. replaceSettings.set(e.replace);
  19250. });
  19251. const getData = () => {
  19252. const fromSettings = replaceSettings.get() ? [] : settingsFormats.get();
  19253. const fromEvents = eventsFormats.get();
  19254. return fromSettings.concat(fromEvents);
  19255. };
  19256. return { getData };
  19257. };
  19258. const isElement = node => isNonNullable(node) && node.nodeType === 1;
  19259. const trim = global$1.trim;
  19260. const hasContentEditableState = value => {
  19261. return node => {
  19262. if (isElement(node)) {
  19263. if (node.contentEditable === value) {
  19264. return true;
  19265. }
  19266. if (node.getAttribute('data-mce-contenteditable') === value) {
  19267. return true;
  19268. }
  19269. }
  19270. return false;
  19271. };
  19272. };
  19273. const isContentEditableTrue = hasContentEditableState('true');
  19274. const isContentEditableFalse = hasContentEditableState('false');
  19275. const create = (type, title, url, level, attach) => ({
  19276. type,
  19277. title,
  19278. url,
  19279. level,
  19280. attach
  19281. });
  19282. const isChildOfContentEditableTrue = node => {
  19283. let tempNode = node;
  19284. while (tempNode = tempNode.parentNode) {
  19285. const value = tempNode.contentEditable;
  19286. if (value && value !== 'inherit') {
  19287. return isContentEditableTrue(tempNode);
  19288. }
  19289. }
  19290. return false;
  19291. };
  19292. const select = (selector, root) => {
  19293. return map$2(descendants(SugarElement.fromDom(root), selector), element => {
  19294. return element.dom;
  19295. });
  19296. };
  19297. const getElementText = elm => {
  19298. return elm.innerText || elm.textContent;
  19299. };
  19300. const getOrGenerateId = elm => {
  19301. return elm.id ? elm.id : generate$6('h');
  19302. };
  19303. const isAnchor = elm => {
  19304. return elm && elm.nodeName === 'A' && (elm.id || elm.name) !== undefined;
  19305. };
  19306. const isValidAnchor = elm => {
  19307. return isAnchor(elm) && isEditable(elm);
  19308. };
  19309. const isHeader = elm => {
  19310. return elm && /^(H[1-6])$/.test(elm.nodeName);
  19311. };
  19312. const isEditable = elm => {
  19313. return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
  19314. };
  19315. const isValidHeader = elm => {
  19316. return isHeader(elm) && isEditable(elm);
  19317. };
  19318. const getLevel = elm => {
  19319. return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
  19320. };
  19321. const headerTarget = elm => {
  19322. var _a;
  19323. const headerId = getOrGenerateId(elm);
  19324. const attach = () => {
  19325. elm.id = headerId;
  19326. };
  19327. return create('header', (_a = getElementText(elm)) !== null && _a !== void 0 ? _a : '', '#' + headerId, getLevel(elm), attach);
  19328. };
  19329. const anchorTarget = elm => {
  19330. const anchorId = elm.id || elm.name;
  19331. const anchorText = getElementText(elm);
  19332. return create('anchor', anchorText ? anchorText : '#' + anchorId, '#' + anchorId, 0, noop);
  19333. };
  19334. const getHeaderTargets = elms => {
  19335. return map$2(filter$2(elms, isValidHeader), headerTarget);
  19336. };
  19337. const getAnchorTargets = elms => {
  19338. return map$2(filter$2(elms, isValidAnchor), anchorTarget);
  19339. };
  19340. const getTargetElements = elm => {
  19341. const elms = select('h1,h2,h3,h4,h5,h6,a:not([href])', elm);
  19342. return elms;
  19343. };
  19344. const hasTitle = target => {
  19345. return trim(target.title).length > 0;
  19346. };
  19347. const find = elm => {
  19348. const elms = getTargetElements(elm);
  19349. return filter$2(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
  19350. };
  19351. const LinkTargets = { find };
  19352. const STORAGE_KEY = 'tinymce-url-history';
  19353. const HISTORY_LENGTH = 5;
  19354. const isHttpUrl = url => isString(url) && /^https?/.test(url);
  19355. const isArrayOfUrl = a => isArray(a) && a.length <= HISTORY_LENGTH && forall(a, isHttpUrl);
  19356. const isRecordOfUrlArray = r => isObject(r) && find$4(r, value => !isArrayOfUrl(value)).isNone();
  19357. const getAllHistory = () => {
  19358. const unparsedHistory = global$4.getItem(STORAGE_KEY);
  19359. if (unparsedHistory === null) {
  19360. return {};
  19361. }
  19362. let history;
  19363. try {
  19364. history = JSON.parse(unparsedHistory);
  19365. } catch (e) {
  19366. if (e instanceof SyntaxError) {
  19367. console.log('Local storage ' + STORAGE_KEY + ' was not valid JSON', e);
  19368. return {};
  19369. }
  19370. throw e;
  19371. }
  19372. if (!isRecordOfUrlArray(history)) {
  19373. console.log('Local storage ' + STORAGE_KEY + ' was not valid format', history);
  19374. return {};
  19375. }
  19376. return history;
  19377. };
  19378. const setAllHistory = history => {
  19379. if (!isRecordOfUrlArray(history)) {
  19380. throw new Error('Bad format for history:\n' + JSON.stringify(history));
  19381. }
  19382. global$4.setItem(STORAGE_KEY, JSON.stringify(history));
  19383. };
  19384. const getHistory = fileType => {
  19385. const history = getAllHistory();
  19386. return get$g(history, fileType).getOr([]);
  19387. };
  19388. const addToHistory = (url, fileType) => {
  19389. if (!isHttpUrl(url)) {
  19390. return;
  19391. }
  19392. const history = getAllHistory();
  19393. const items = get$g(history, fileType).getOr([]);
  19394. const itemsWithoutUrl = filter$2(items, item => item !== url);
  19395. history[fileType] = [url].concat(itemsWithoutUrl).slice(0, HISTORY_LENGTH);
  19396. setAllHistory(history);
  19397. };
  19398. const isTruthy = value => !!value;
  19399. const makeMap = value => map$1(global$1.makeMap(value, /[, ]/), isTruthy);
  19400. const getPicker = editor => Optional.from(getFilePickerCallback(editor));
  19401. const getPickerTypes = editor => {
  19402. const optFileTypes = Optional.from(getFilePickerTypes(editor)).filter(isTruthy).map(makeMap);
  19403. return getPicker(editor).fold(never, _picker => optFileTypes.fold(always, types => keys(types).length > 0 ? types : false));
  19404. };
  19405. const getPickerSetting = (editor, filetype) => {
  19406. const pickerTypes = getPickerTypes(editor);
  19407. if (isBoolean(pickerTypes)) {
  19408. return pickerTypes ? getPicker(editor) : Optional.none();
  19409. } else {
  19410. return pickerTypes[filetype] ? getPicker(editor) : Optional.none();
  19411. }
  19412. };
  19413. const getUrlPicker = (editor, filetype) => getPickerSetting(editor, filetype).map(picker => entry => Future.nu(completer => {
  19414. const handler = (value, meta) => {
  19415. if (!isString(value)) {
  19416. throw new Error('Expected value to be string');
  19417. }
  19418. if (meta !== undefined && !isObject(meta)) {
  19419. throw new Error('Expected meta to be a object');
  19420. }
  19421. const r = {
  19422. value,
  19423. meta
  19424. };
  19425. completer(r);
  19426. };
  19427. const meta = {
  19428. filetype,
  19429. fieldname: entry.fieldname,
  19430. ...Optional.from(entry.meta).getOr({})
  19431. };
  19432. picker.call(editor, handler, entry.value, meta);
  19433. }));
  19434. const getTextSetting = value => Optional.from(value).filter(isString).getOrUndefined();
  19435. const getLinkInformation = editor => {
  19436. if (!useTypeaheadUrls(editor)) {
  19437. return Optional.none();
  19438. }
  19439. return Optional.some({
  19440. targets: LinkTargets.find(editor.getBody()),
  19441. anchorTop: getTextSetting(getAnchorTop(editor)),
  19442. anchorBottom: getTextSetting(getAnchorBottom(editor))
  19443. });
  19444. };
  19445. const getValidationHandler = editor => Optional.from(getFilePickerValidatorHandler(editor));
  19446. const UrlInputBackstage = editor => ({
  19447. getHistory,
  19448. addToHistory,
  19449. getLinkInformation: () => getLinkInformation(editor),
  19450. getValidationHandler: () => getValidationHandler(editor),
  19451. getUrlPicker: filetype => getUrlPicker(editor, filetype)
  19452. });
  19453. const init$6 = (lazySinks, editor, lazyAnchorbar, lazyBottomAnchorBar) => {
  19454. const contextMenuState = Cell(false);
  19455. const toolbar = HeaderBackstage(editor);
  19456. const providers = {
  19457. icons: () => editor.ui.registry.getAll().icons,
  19458. menuItems: () => editor.ui.registry.getAll().menuItems,
  19459. translate: global$8.translate,
  19460. isDisabled: () => editor.mode.isReadOnly() || !editor.ui.isEnabled(),
  19461. getOption: editor.options.get
  19462. };
  19463. const urlinput = UrlInputBackstage(editor);
  19464. const styles = init$7(editor);
  19465. const colorinput = ColorInputBackstage(editor);
  19466. const dialogSettings = DialogBackstage(editor);
  19467. const isContextMenuOpen = () => contextMenuState.get();
  19468. const setContextMenuState = state => contextMenuState.set(state);
  19469. const commonBackstage = {
  19470. shared: {
  19471. providers,
  19472. anchors: getAnchors(editor, lazyAnchorbar, lazyBottomAnchorBar, toolbar.isPositionedAtTop),
  19473. header: toolbar
  19474. },
  19475. urlinput,
  19476. styles,
  19477. colorinput,
  19478. dialog: dialogSettings,
  19479. isContextMenuOpen,
  19480. setContextMenuState
  19481. };
  19482. const popupBackstage = {
  19483. ...commonBackstage,
  19484. shared: {
  19485. ...commonBackstage.shared,
  19486. interpreter: s => interpretWithoutForm(s, {}, popupBackstage),
  19487. getSink: lazySinks.popup
  19488. }
  19489. };
  19490. const dialogBackstage = {
  19491. ...commonBackstage,
  19492. shared: {
  19493. ...commonBackstage.shared,
  19494. interpreter: s => interpretWithoutForm(s, {}, dialogBackstage),
  19495. getSink: lazySinks.dialog
  19496. }
  19497. };
  19498. return {
  19499. popup: popupBackstage,
  19500. dialog: dialogBackstage
  19501. };
  19502. };
  19503. const setup$b = (editor, mothership, uiMotherships) => {
  19504. const broadcastEvent = (name, evt) => {
  19505. each$1([
  19506. mothership,
  19507. ...uiMotherships
  19508. ], m => {
  19509. m.broadcastEvent(name, evt);
  19510. });
  19511. };
  19512. const broadcastOn = (channel, message) => {
  19513. each$1([
  19514. mothership,
  19515. ...uiMotherships
  19516. ], m => {
  19517. m.broadcastOn([channel], message);
  19518. });
  19519. };
  19520. const fireDismissPopups = evt => broadcastOn(dismissPopups(), { target: evt.target });
  19521. const doc = getDocument();
  19522. const onTouchstart = bind(doc, 'touchstart', fireDismissPopups);
  19523. const onTouchmove = bind(doc, 'touchmove', evt => broadcastEvent(documentTouchmove(), evt));
  19524. const onTouchend = bind(doc, 'touchend', evt => broadcastEvent(documentTouchend(), evt));
  19525. const onMousedown = bind(doc, 'mousedown', fireDismissPopups);
  19526. const onMouseup = bind(doc, 'mouseup', evt => {
  19527. if (evt.raw.button === 0) {
  19528. broadcastOn(mouseReleased(), { target: evt.target });
  19529. }
  19530. });
  19531. const onContentClick = raw => broadcastOn(dismissPopups(), { target: SugarElement.fromDom(raw.target) });
  19532. const onContentMouseup = raw => {
  19533. if (raw.button === 0) {
  19534. broadcastOn(mouseReleased(), { target: SugarElement.fromDom(raw.target) });
  19535. }
  19536. };
  19537. const onContentMousedown = () => {
  19538. each$1(editor.editorManager.get(), loopEditor => {
  19539. if (editor !== loopEditor) {
  19540. loopEditor.dispatch('DismissPopups', { relatedTarget: editor });
  19541. }
  19542. });
  19543. };
  19544. const onWindowScroll = evt => broadcastEvent(windowScroll(), fromRawEvent(evt));
  19545. const onWindowResize = evt => {
  19546. broadcastOn(repositionPopups(), {});
  19547. broadcastEvent(windowResize(), fromRawEvent(evt));
  19548. };
  19549. const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
  19550. const onElementScroll = capture(dos, 'scroll', evt => {
  19551. requestAnimationFrame(() => {
  19552. const c = editor.getContainer();
  19553. if (c !== undefined && c !== null) {
  19554. const optScrollingContext = detectWhenSplitUiMode(editor, mothership.element);
  19555. const scrollers = optScrollingContext.map(sc => [
  19556. sc.element,
  19557. ...sc.others
  19558. ]).getOr([]);
  19559. if (exists(scrollers, s => eq(s, evt.target))) {
  19560. editor.dispatch('ElementScroll', { target: evt.target.dom });
  19561. broadcastEvent(externalElementScroll(), evt);
  19562. }
  19563. }
  19564. });
  19565. });
  19566. const onEditorResize = () => broadcastOn(repositionPopups(), {});
  19567. const onEditorProgress = evt => {
  19568. if (evt.state) {
  19569. broadcastOn(dismissPopups(), { target: SugarElement.fromDom(editor.getContainer()) });
  19570. }
  19571. };
  19572. const onDismissPopups = event => {
  19573. broadcastOn(dismissPopups(), { target: SugarElement.fromDom(event.relatedTarget.getContainer()) });
  19574. };
  19575. editor.on('PostRender', () => {
  19576. editor.on('click', onContentClick);
  19577. editor.on('tap', onContentClick);
  19578. editor.on('mouseup', onContentMouseup);
  19579. editor.on('mousedown', onContentMousedown);
  19580. editor.on('ScrollWindow', onWindowScroll);
  19581. editor.on('ResizeWindow', onWindowResize);
  19582. editor.on('ResizeEditor', onEditorResize);
  19583. editor.on('AfterProgressState', onEditorProgress);
  19584. editor.on('DismissPopups', onDismissPopups);
  19585. });
  19586. editor.on('remove', () => {
  19587. editor.off('click', onContentClick);
  19588. editor.off('tap', onContentClick);
  19589. editor.off('mouseup', onContentMouseup);
  19590. editor.off('mousedown', onContentMousedown);
  19591. editor.off('ScrollWindow', onWindowScroll);
  19592. editor.off('ResizeWindow', onWindowResize);
  19593. editor.off('ResizeEditor', onEditorResize);
  19594. editor.off('AfterProgressState', onEditorProgress);
  19595. editor.off('DismissPopups', onDismissPopups);
  19596. onMousedown.unbind();
  19597. onTouchstart.unbind();
  19598. onTouchmove.unbind();
  19599. onTouchend.unbind();
  19600. onMouseup.unbind();
  19601. onElementScroll.unbind();
  19602. });
  19603. editor.on('detach', () => {
  19604. each$1([
  19605. mothership,
  19606. ...uiMotherships
  19607. ], detachSystem);
  19608. each$1([
  19609. mothership,
  19610. ...uiMotherships
  19611. ], m => m.destroy());
  19612. });
  19613. };
  19614. const parts$a = AlloyParts;
  19615. const partType = PartType;
  19616. const schema$f = constant$1([
  19617. defaulted('shell', false),
  19618. required$1('makeItem'),
  19619. defaulted('setupItem', noop),
  19620. SketchBehaviours.field('listBehaviours', [Replacing])
  19621. ]);
  19622. const customListDetail = () => ({ behaviours: derive$1([Replacing.config({})]) });
  19623. const itemsPart = optional({
  19624. name: 'items',
  19625. overrides: customListDetail
  19626. });
  19627. const parts$9 = constant$1([itemsPart]);
  19628. const name = constant$1('CustomList');
  19629. const factory$f = (detail, components, _spec, _external) => {
  19630. const setItems = (list, items) => {
  19631. getListContainer(list).fold(() => {
  19632. console.error('Custom List was defined to not be a shell, but no item container was specified in components');
  19633. throw new Error('Custom List was defined to not be a shell, but no item container was specified in components');
  19634. }, container => {
  19635. const itemComps = Replacing.contents(container);
  19636. const numListsRequired = items.length;
  19637. const numListsToAdd = numListsRequired - itemComps.length;
  19638. const itemsToAdd = numListsToAdd > 0 ? range$2(numListsToAdd, () => detail.makeItem()) : [];
  19639. const itemsToRemove = itemComps.slice(numListsRequired);
  19640. each$1(itemsToRemove, item => Replacing.remove(container, item));
  19641. each$1(itemsToAdd, item => Replacing.append(container, item));
  19642. const builtLists = Replacing.contents(container);
  19643. each$1(builtLists, (item, i) => {
  19644. detail.setupItem(list, item, items[i], i);
  19645. });
  19646. });
  19647. };
  19648. const extra = detail.shell ? {
  19649. behaviours: [Replacing.config({})],
  19650. components: []
  19651. } : {
  19652. behaviours: [],
  19653. components
  19654. };
  19655. const getListContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'items');
  19656. return {
  19657. uid: detail.uid,
  19658. dom: detail.dom,
  19659. components: extra.components,
  19660. behaviours: augment(detail.listBehaviours, extra.behaviours),
  19661. apis: { setItems }
  19662. };
  19663. };
  19664. const CustomList = composite({
  19665. name: name(),
  19666. configFields: schema$f(),
  19667. partFields: parts$9(),
  19668. factory: factory$f,
  19669. apis: {
  19670. setItems: (apis, list, items) => {
  19671. apis.setItems(list, items);
  19672. }
  19673. }
  19674. });
  19675. const schema$e = constant$1([
  19676. required$1('dom'),
  19677. defaulted('shell', true),
  19678. field('toolbarBehaviours', [Replacing])
  19679. ]);
  19680. const enhanceGroups = () => ({ behaviours: derive$1([Replacing.config({})]) });
  19681. const parts$8 = constant$1([optional({
  19682. name: 'groups',
  19683. overrides: enhanceGroups
  19684. })]);
  19685. const factory$e = (detail, components, _spec, _externals) => {
  19686. const setGroups = (toolbar, groups) => {
  19687. getGroupContainer(toolbar).fold(() => {
  19688. console.error('Toolbar was defined to not be a shell, but no groups container was specified in components');
  19689. throw new Error('Toolbar was defined to not be a shell, but no groups container was specified in components');
  19690. }, container => {
  19691. Replacing.set(container, groups);
  19692. });
  19693. };
  19694. const getGroupContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'groups');
  19695. const extra = detail.shell ? {
  19696. behaviours: [Replacing.config({})],
  19697. components: []
  19698. } : {
  19699. behaviours: [],
  19700. components
  19701. };
  19702. return {
  19703. uid: detail.uid,
  19704. dom: detail.dom,
  19705. components: extra.components,
  19706. behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
  19707. apis: {
  19708. setGroups,
  19709. refresh: noop
  19710. },
  19711. domModification: { attributes: { role: 'group' } }
  19712. };
  19713. };
  19714. const Toolbar = composite({
  19715. name: 'Toolbar',
  19716. configFields: schema$e(),
  19717. partFields: parts$8(),
  19718. factory: factory$e,
  19719. apis: {
  19720. setGroups: (apis, toolbar, groups) => {
  19721. apis.setGroups(toolbar, groups);
  19722. }
  19723. }
  19724. });
  19725. const setup$a = noop;
  19726. const isDocked$2 = never;
  19727. const getBehaviours$1 = constant$1([]);
  19728. var StaticHeader = /*#__PURE__*/Object.freeze({
  19729. __proto__: null,
  19730. setup: setup$a,
  19731. isDocked: isDocked$2,
  19732. getBehaviours: getBehaviours$1
  19733. });
  19734. const getOffsetParent = element => {
  19735. const isFixed = is$1(getRaw(element, 'position'), 'fixed');
  19736. const offsetParent$1 = isFixed ? Optional.none() : offsetParent(element);
  19737. return offsetParent$1.orThunk(() => {
  19738. const marker = SugarElement.fromTag('span');
  19739. return parent(element).bind(parent => {
  19740. append$2(parent, marker);
  19741. const offsetParent$1 = offsetParent(marker);
  19742. remove$5(marker);
  19743. return offsetParent$1;
  19744. });
  19745. });
  19746. };
  19747. const getOrigin = element => getOffsetParent(element).map(absolute$3).getOrThunk(() => SugarPosition(0, 0));
  19748. const appear = (component, contextualInfo) => {
  19749. const elem = component.element;
  19750. add$2(elem, contextualInfo.transitionClass);
  19751. remove$2(elem, contextualInfo.fadeOutClass);
  19752. add$2(elem, contextualInfo.fadeInClass);
  19753. contextualInfo.onShow(component);
  19754. };
  19755. const disappear = (component, contextualInfo) => {
  19756. const elem = component.element;
  19757. add$2(elem, contextualInfo.transitionClass);
  19758. remove$2(elem, contextualInfo.fadeInClass);
  19759. add$2(elem, contextualInfo.fadeOutClass);
  19760. contextualInfo.onHide(component);
  19761. };
  19762. const isPartiallyVisible = (box, bounds) => box.y < bounds.bottom && box.bottom > bounds.y;
  19763. const isTopCompletelyVisible = (box, bounds) => box.y >= bounds.y;
  19764. const isBottomCompletelyVisible = (box, bounds) => box.bottom <= bounds.bottom;
  19765. const forceTopPosition = (winBox, leftX, viewport) => ({
  19766. location: 'top',
  19767. leftX,
  19768. topY: viewport.bounds.y - winBox.y
  19769. });
  19770. const forceBottomPosition = (winBox, leftX, viewport) => ({
  19771. location: 'bottom',
  19772. leftX,
  19773. bottomY: winBox.bottom - viewport.bounds.bottom
  19774. });
  19775. const getDockedLeftPosition = bounds => {
  19776. return bounds.box.x - bounds.win.x;
  19777. };
  19778. const tryDockingPosition = (modes, bounds, viewport) => {
  19779. const winBox = bounds.win;
  19780. const box = bounds.box;
  19781. const leftX = getDockedLeftPosition(bounds);
  19782. return findMap(modes, mode => {
  19783. switch (mode) {
  19784. case 'bottom':
  19785. return !isBottomCompletelyVisible(box, viewport.bounds) ? Optional.some(forceBottomPosition(winBox, leftX, viewport)) : Optional.none();
  19786. case 'top':
  19787. return !isTopCompletelyVisible(box, viewport.bounds) ? Optional.some(forceTopPosition(winBox, leftX, viewport)) : Optional.none();
  19788. default:
  19789. return Optional.none();
  19790. }
  19791. }).getOr({ location: 'no-dock' });
  19792. };
  19793. const isVisibleForModes = (modes, box, viewport) => forall(modes, mode => {
  19794. switch (mode) {
  19795. case 'bottom':
  19796. return isBottomCompletelyVisible(box, viewport.bounds);
  19797. case 'top':
  19798. return isTopCompletelyVisible(box, viewport.bounds);
  19799. }
  19800. });
  19801. const getXYForRestoring = (pos, viewport) => {
  19802. const priorY = viewport.optScrollEnv.fold(constant$1(pos.bounds.y), scrollEnv => scrollEnv.scrollElmTop + (pos.bounds.y - scrollEnv.currentScrollTop));
  19803. return SugarPosition(pos.bounds.x, priorY);
  19804. };
  19805. const getXYForSaving = (box, viewport) => {
  19806. const priorY = viewport.optScrollEnv.fold(constant$1(box.y), scrollEnv => box.y + scrollEnv.currentScrollTop - scrollEnv.scrollElmTop);
  19807. return SugarPosition(box.x, priorY);
  19808. };
  19809. const getPrior = (elem, viewport, state) => state.getInitialPos().map(pos => {
  19810. const xy = getXYForRestoring(pos, viewport);
  19811. return {
  19812. box: bounds(xy.left, xy.top, get$c(elem), get$d(elem)),
  19813. location: pos.location
  19814. };
  19815. });
  19816. const storePrior = (elem, box, viewport, state, decision) => {
  19817. const xy = getXYForSaving(box, viewport);
  19818. const bounds$1 = bounds(xy.left, xy.top, box.width, box.height);
  19819. state.setInitialPos({
  19820. style: getAllRaw(elem),
  19821. position: get$e(elem, 'position') || 'static',
  19822. bounds: bounds$1,
  19823. location: decision.location
  19824. });
  19825. };
  19826. const storePriorIfNone = (elem, box, viewport, state, decision) => {
  19827. state.getInitialPos().fold(() => storePrior(elem, box, viewport, state, decision), () => noop);
  19828. };
  19829. const revertToOriginal = (elem, box, state) => state.getInitialPos().bind(position => {
  19830. var _a;
  19831. state.clearInitialPos();
  19832. switch (position.position) {
  19833. case 'static':
  19834. return Optional.some({ morph: 'static' });
  19835. case 'absolute':
  19836. const offsetParent = getOffsetParent(elem).getOr(body());
  19837. const offsetBox = box$1(offsetParent);
  19838. const scrollDelta = (_a = offsetParent.dom.scrollTop) !== null && _a !== void 0 ? _a : 0;
  19839. return Optional.some({
  19840. morph: 'absolute',
  19841. positionCss: NuPositionCss('absolute', get$g(position.style, 'left').map(_left => box.x - offsetBox.x), get$g(position.style, 'top').map(_top => box.y - offsetBox.y + scrollDelta), get$g(position.style, 'right').map(_right => offsetBox.right - box.right), get$g(position.style, 'bottom').map(_bottom => offsetBox.bottom - box.bottom))
  19842. });
  19843. default:
  19844. return Optional.none();
  19845. }
  19846. });
  19847. const tryMorphToOriginal = (elem, viewport, state) => getPrior(elem, viewport, state).filter(({box}) => isVisibleForModes(state.getModes(), box, viewport)).bind(({box}) => revertToOriginal(elem, box, state));
  19848. const tryDecisionToFixedMorph = decision => {
  19849. switch (decision.location) {
  19850. case 'top': {
  19851. return Optional.some({
  19852. morph: 'fixed',
  19853. positionCss: NuPositionCss('fixed', Optional.some(decision.leftX), Optional.some(decision.topY), Optional.none(), Optional.none())
  19854. });
  19855. }
  19856. case 'bottom': {
  19857. return Optional.some({
  19858. morph: 'fixed',
  19859. positionCss: NuPositionCss('fixed', Optional.some(decision.leftX), Optional.none(), Optional.none(), Optional.some(decision.bottomY))
  19860. });
  19861. }
  19862. default:
  19863. return Optional.none();
  19864. }
  19865. };
  19866. const tryMorphToFixed = (elem, viewport, state) => {
  19867. const box = box$1(elem);
  19868. const winBox = win();
  19869. const decision = tryDockingPosition(state.getModes(), {
  19870. win: winBox,
  19871. box
  19872. }, viewport);
  19873. if (decision.location === 'top' || decision.location === 'bottom') {
  19874. storePrior(elem, box, viewport, state, decision);
  19875. return tryDecisionToFixedMorph(decision);
  19876. } else {
  19877. return Optional.none();
  19878. }
  19879. };
  19880. const tryMorphToOriginalOrUpdateFixed = (elem, viewport, state) => {
  19881. return tryMorphToOriginal(elem, viewport, state).orThunk(() => {
  19882. return viewport.optScrollEnv.bind(_ => getPrior(elem, viewport, state)).bind(({box, location}) => {
  19883. const winBox = win();
  19884. const leftX = getDockedLeftPosition({
  19885. win: winBox,
  19886. box
  19887. });
  19888. const decision = location === 'top' ? forceTopPosition(winBox, leftX, viewport) : forceBottomPosition(winBox, leftX, viewport);
  19889. return tryDecisionToFixedMorph(decision);
  19890. });
  19891. });
  19892. };
  19893. const tryMorph = (component, viewport, state) => {
  19894. const elem = component.element;
  19895. const isDocked = is$1(getRaw(elem, 'position'), 'fixed');
  19896. return isDocked ? tryMorphToOriginalOrUpdateFixed(elem, viewport, state) : tryMorphToFixed(elem, viewport, state);
  19897. };
  19898. const calculateMorphToOriginal = (component, viewport, state) => {
  19899. const elem = component.element;
  19900. return getPrior(elem, viewport, state).bind(({box}) => revertToOriginal(elem, box, state));
  19901. };
  19902. const forceDockWith = (elem, viewport, state, getDecision) => {
  19903. const box = box$1(elem);
  19904. const winBox = win();
  19905. const leftX = getDockedLeftPosition({
  19906. win: winBox,
  19907. box
  19908. });
  19909. const decision = getDecision(winBox, leftX, viewport);
  19910. if (decision.location === 'bottom' || decision.location === 'top') {
  19911. storePriorIfNone(elem, box, viewport, state, decision);
  19912. return tryDecisionToFixedMorph(decision);
  19913. } else {
  19914. return Optional.none();
  19915. }
  19916. };
  19917. const morphToStatic = (component, config, state) => {
  19918. state.setDocked(false);
  19919. each$1([
  19920. 'left',
  19921. 'right',
  19922. 'top',
  19923. 'bottom',
  19924. 'position'
  19925. ], prop => remove$6(component.element, prop));
  19926. config.onUndocked(component);
  19927. };
  19928. const morphToCoord = (component, config, state, position) => {
  19929. const isDocked = position.position === 'fixed';
  19930. state.setDocked(isDocked);
  19931. applyPositionCss(component.element, position);
  19932. const method = isDocked ? config.onDocked : config.onUndocked;
  19933. method(component);
  19934. };
  19935. const updateVisibility = (component, config, state, viewport, morphToDocked = false) => {
  19936. config.contextual.each(contextInfo => {
  19937. contextInfo.lazyContext(component).each(box => {
  19938. const isVisible = isPartiallyVisible(box, viewport.bounds);
  19939. if (isVisible !== state.isVisible()) {
  19940. state.setVisible(isVisible);
  19941. if (morphToDocked && !isVisible) {
  19942. add$1(component.element, [contextInfo.fadeOutClass]);
  19943. contextInfo.onHide(component);
  19944. } else {
  19945. const method = isVisible ? appear : disappear;
  19946. method(component, contextInfo);
  19947. }
  19948. }
  19949. });
  19950. });
  19951. };
  19952. const applyFixedMorph = (component, config, state, viewport, morph) => {
  19953. updateVisibility(component, config, state, viewport, true);
  19954. morphToCoord(component, config, state, morph.positionCss);
  19955. };
  19956. const applyMorph = (component, config, state, viewport, morph) => {
  19957. switch (morph.morph) {
  19958. case 'static': {
  19959. return morphToStatic(component, config, state);
  19960. }
  19961. case 'absolute': {
  19962. return morphToCoord(component, config, state, morph.positionCss);
  19963. }
  19964. case 'fixed': {
  19965. return applyFixedMorph(component, config, state, viewport, morph);
  19966. }
  19967. }
  19968. };
  19969. const refreshInternal = (component, config, state) => {
  19970. const viewport = config.lazyViewport(component);
  19971. updateVisibility(component, config, state, viewport);
  19972. tryMorph(component, viewport, state).each(morph => {
  19973. applyMorph(component, config, state, viewport, morph);
  19974. });
  19975. };
  19976. const resetInternal = (component, config, state) => {
  19977. const elem = component.element;
  19978. state.setDocked(false);
  19979. const viewport = config.lazyViewport(component);
  19980. calculateMorphToOriginal(component, viewport, state).each(staticOrAbsoluteMorph => {
  19981. switch (staticOrAbsoluteMorph.morph) {
  19982. case 'static': {
  19983. morphToStatic(component, config, state);
  19984. break;
  19985. }
  19986. case 'absolute': {
  19987. morphToCoord(component, config, state, staticOrAbsoluteMorph.positionCss);
  19988. break;
  19989. }
  19990. }
  19991. });
  19992. state.setVisible(true);
  19993. config.contextual.each(contextInfo => {
  19994. remove$1(elem, [
  19995. contextInfo.fadeInClass,
  19996. contextInfo.fadeOutClass,
  19997. contextInfo.transitionClass
  19998. ]);
  19999. contextInfo.onShow(component);
  20000. });
  20001. refresh$3(component, config, state);
  20002. };
  20003. const refresh$3 = (component, config, state) => {
  20004. if (component.getSystem().isConnected()) {
  20005. refreshInternal(component, config, state);
  20006. }
  20007. };
  20008. const reset = (component, config, state) => {
  20009. if (state.isDocked()) {
  20010. resetInternal(component, config, state);
  20011. }
  20012. };
  20013. const forceDockWithDecision = getDecision => (component, config, state) => {
  20014. const viewport = config.lazyViewport(component);
  20015. const optMorph = forceDockWith(component.element, viewport, state, getDecision);
  20016. optMorph.each(morph => {
  20017. applyFixedMorph(component, config, state, viewport, morph);
  20018. });
  20019. };
  20020. const forceDockToTop = forceDockWithDecision(forceTopPosition);
  20021. const forceDockToBottom = forceDockWithDecision(forceBottomPosition);
  20022. const isDocked$1 = (component, config, state) => state.isDocked();
  20023. const setModes = (component, config, state, modes) => state.setModes(modes);
  20024. const getModes = (component, config, state) => state.getModes();
  20025. var DockingApis = /*#__PURE__*/Object.freeze({
  20026. __proto__: null,
  20027. refresh: refresh$3,
  20028. reset: reset,
  20029. isDocked: isDocked$1,
  20030. getModes: getModes,
  20031. setModes: setModes,
  20032. forceDockToTop: forceDockToTop,
  20033. forceDockToBottom: forceDockToBottom
  20034. });
  20035. const events$4 = (dockInfo, dockState) => derive$2([
  20036. runOnSource(transitionend(), (component, simulatedEvent) => {
  20037. dockInfo.contextual.each(contextInfo => {
  20038. if (has(component.element, contextInfo.transitionClass)) {
  20039. remove$1(component.element, [
  20040. contextInfo.transitionClass,
  20041. contextInfo.fadeInClass
  20042. ]);
  20043. const notify = dockState.isVisible() ? contextInfo.onShown : contextInfo.onHidden;
  20044. notify(component);
  20045. }
  20046. simulatedEvent.stop();
  20047. });
  20048. }),
  20049. run$1(windowScroll(), (component, _) => {
  20050. refresh$3(component, dockInfo, dockState);
  20051. }),
  20052. run$1(externalElementScroll(), (component, _) => {
  20053. refresh$3(component, dockInfo, dockState);
  20054. }),
  20055. run$1(windowResize(), (component, _) => {
  20056. reset(component, dockInfo, dockState);
  20057. })
  20058. ]);
  20059. var ActiveDocking = /*#__PURE__*/Object.freeze({
  20060. __proto__: null,
  20061. events: events$4
  20062. });
  20063. var DockingSchema = [
  20064. optionObjOf('contextual', [
  20065. requiredString('fadeInClass'),
  20066. requiredString('fadeOutClass'),
  20067. requiredString('transitionClass'),
  20068. requiredFunction('lazyContext'),
  20069. onHandler('onShow'),
  20070. onHandler('onShown'),
  20071. onHandler('onHide'),
  20072. onHandler('onHidden')
  20073. ]),
  20074. defaultedFunction('lazyViewport', () => ({
  20075. bounds: win(),
  20076. optScrollEnv: Optional.none()
  20077. })),
  20078. defaultedArrayOf('modes', [
  20079. 'top',
  20080. 'bottom'
  20081. ], string),
  20082. onHandler('onDocked'),
  20083. onHandler('onUndocked')
  20084. ];
  20085. const init$5 = spec => {
  20086. const docked = Cell(false);
  20087. const visible = Cell(true);
  20088. const initialBounds = value$2();
  20089. const modes = Cell(spec.modes);
  20090. const readState = () => `docked: ${ docked.get() }, visible: ${ visible.get() }, modes: ${ modes.get().join(',') }`;
  20091. return nu$8({
  20092. isDocked: docked.get,
  20093. setDocked: docked.set,
  20094. getInitialPos: initialBounds.get,
  20095. setInitialPos: initialBounds.set,
  20096. clearInitialPos: initialBounds.clear,
  20097. isVisible: visible.get,
  20098. setVisible: visible.set,
  20099. getModes: modes.get,
  20100. setModes: modes.set,
  20101. readState
  20102. });
  20103. };
  20104. var DockingState = /*#__PURE__*/Object.freeze({
  20105. __proto__: null,
  20106. init: init$5
  20107. });
  20108. const Docking = create$4({
  20109. fields: DockingSchema,
  20110. name: 'docking',
  20111. active: ActiveDocking,
  20112. apis: DockingApis,
  20113. state: DockingState
  20114. });
  20115. const toolbarHeightChange = constant$1(generate$6('toolbar-height-change'));
  20116. const visibility = {
  20117. fadeInClass: 'tox-editor-dock-fadein',
  20118. fadeOutClass: 'tox-editor-dock-fadeout',
  20119. transitionClass: 'tox-editor-dock-transition'
  20120. };
  20121. const editorStickyOnClass = 'tox-tinymce--toolbar-sticky-on';
  20122. const editorStickyOffClass = 'tox-tinymce--toolbar-sticky-off';
  20123. const scrollFromBehindHeader = (e, containerHeader) => {
  20124. const doc = owner$4(containerHeader);
  20125. const win = defaultView(containerHeader);
  20126. const viewHeight = win.dom.innerHeight;
  20127. const scrollPos = get$b(doc);
  20128. const markerElement = SugarElement.fromDom(e.elm);
  20129. const markerPos = absolute$2(markerElement);
  20130. const markerHeight = get$d(markerElement);
  20131. const markerTop = markerPos.y;
  20132. const markerBottom = markerTop + markerHeight;
  20133. const editorHeaderPos = absolute$3(containerHeader);
  20134. const editorHeaderHeight = get$d(containerHeader);
  20135. const editorHeaderTop = editorHeaderPos.top;
  20136. const editorHeaderBottom = editorHeaderTop + editorHeaderHeight;
  20137. const editorHeaderDockedAtTop = Math.abs(editorHeaderTop - scrollPos.top) < 2;
  20138. const editorHeaderDockedAtBottom = Math.abs(editorHeaderBottom - (scrollPos.top + viewHeight)) < 2;
  20139. if (editorHeaderDockedAtTop && markerTop < editorHeaderBottom) {
  20140. to(scrollPos.left, markerTop - editorHeaderHeight, doc);
  20141. } else if (editorHeaderDockedAtBottom && markerBottom > editorHeaderTop) {
  20142. const y = markerTop - viewHeight + markerHeight + editorHeaderHeight;
  20143. to(scrollPos.left, y, doc);
  20144. }
  20145. };
  20146. const isDockedMode = (header, mode) => contains$2(Docking.getModes(header), mode);
  20147. const updateIframeContentFlow = header => {
  20148. const getOccupiedHeight = elm => getOuter$2(elm) + (parseInt(get$e(elm, 'margin-top'), 10) || 0) + (parseInt(get$e(elm, 'margin-bottom'), 10) || 0);
  20149. const elm = header.element;
  20150. parentElement(elm).each(parentElem => {
  20151. const padding = 'padding-' + Docking.getModes(header)[0];
  20152. if (Docking.isDocked(header)) {
  20153. const parentWidth = get$c(parentElem);
  20154. set$8(elm, 'width', parentWidth + 'px');
  20155. set$8(parentElem, padding, getOccupiedHeight(elm) + 'px');
  20156. } else {
  20157. remove$6(elm, 'width');
  20158. remove$6(parentElem, padding);
  20159. }
  20160. });
  20161. };
  20162. const updateSinkVisibility = (sinkElem, visible) => {
  20163. if (visible) {
  20164. remove$2(sinkElem, visibility.fadeOutClass);
  20165. add$1(sinkElem, [
  20166. visibility.transitionClass,
  20167. visibility.fadeInClass
  20168. ]);
  20169. } else {
  20170. remove$2(sinkElem, visibility.fadeInClass);
  20171. add$1(sinkElem, [
  20172. visibility.fadeOutClass,
  20173. visibility.transitionClass
  20174. ]);
  20175. }
  20176. };
  20177. const updateEditorClasses = (editor, docked) => {
  20178. const editorContainer = SugarElement.fromDom(editor.getContainer());
  20179. if (docked) {
  20180. add$2(editorContainer, editorStickyOnClass);
  20181. remove$2(editorContainer, editorStickyOffClass);
  20182. } else {
  20183. add$2(editorContainer, editorStickyOffClass);
  20184. remove$2(editorContainer, editorStickyOnClass);
  20185. }
  20186. };
  20187. const restoreFocus = (headerElem, focusedElem) => {
  20188. const ownerDoc = owner$4(focusedElem);
  20189. active$1(ownerDoc).filter(activeElm => !eq(focusedElem, activeElm)).filter(activeElm => eq(activeElm, SugarElement.fromDom(ownerDoc.dom.body)) || contains(headerElem, activeElm)).each(() => focus$3(focusedElem));
  20190. };
  20191. const findFocusedElem = (rootElm, lazySink) => search(rootElm).orThunk(() => lazySink().toOptional().bind(sink => search(sink.element)));
  20192. const setup$9 = (editor, sharedBackstage, lazyHeader) => {
  20193. if (!editor.inline) {
  20194. if (!sharedBackstage.header.isPositionedAtTop()) {
  20195. editor.on('ResizeEditor', () => {
  20196. lazyHeader().each(Docking.reset);
  20197. });
  20198. }
  20199. editor.on('ResizeWindow ResizeEditor', () => {
  20200. lazyHeader().each(updateIframeContentFlow);
  20201. });
  20202. editor.on('SkinLoaded', () => {
  20203. lazyHeader().each(comp => {
  20204. Docking.isDocked(comp) ? Docking.reset(comp) : Docking.refresh(comp);
  20205. });
  20206. });
  20207. editor.on('FullscreenStateChanged', () => {
  20208. lazyHeader().each(Docking.reset);
  20209. });
  20210. }
  20211. editor.on('AfterScrollIntoView', e => {
  20212. lazyHeader().each(header => {
  20213. Docking.refresh(header);
  20214. const headerElem = header.element;
  20215. if (isVisible(headerElem)) {
  20216. scrollFromBehindHeader(e, headerElem);
  20217. }
  20218. });
  20219. });
  20220. editor.on('PostRender', () => {
  20221. updateEditorClasses(editor, false);
  20222. });
  20223. };
  20224. const isDocked = lazyHeader => lazyHeader().map(Docking.isDocked).getOr(false);
  20225. const getIframeBehaviours = () => [Receiving.config({ channels: { [toolbarHeightChange()]: { onReceive: updateIframeContentFlow } } })];
  20226. const getBehaviours = (editor, sharedBackstage) => {
  20227. const focusedElm = value$2();
  20228. const lazySink = sharedBackstage.getSink;
  20229. const runOnSinkElement = f => {
  20230. lazySink().each(sink => f(sink.element));
  20231. };
  20232. const onDockingSwitch = comp => {
  20233. if (!editor.inline) {
  20234. updateIframeContentFlow(comp);
  20235. }
  20236. updateEditorClasses(editor, Docking.isDocked(comp));
  20237. comp.getSystem().broadcastOn([repositionPopups()], {});
  20238. lazySink().each(sink => sink.getSystem().broadcastOn([repositionPopups()], {}));
  20239. };
  20240. const additionalBehaviours = editor.inline ? [] : getIframeBehaviours();
  20241. return [
  20242. Focusing.config({}),
  20243. Docking.config({
  20244. contextual: {
  20245. lazyContext: comp => {
  20246. const headerHeight = getOuter$2(comp.element);
  20247. const container = editor.inline ? editor.getContentAreaContainer() : editor.getContainer();
  20248. return Optional.from(container).map(c => {
  20249. const box = box$1(SugarElement.fromDom(c));
  20250. const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
  20251. return optScrollingContext.fold(() => {
  20252. const boxHeight = box.height - headerHeight;
  20253. const topBound = box.y + (isDockedMode(comp, 'top') ? 0 : headerHeight);
  20254. return bounds(box.x, topBound, box.width, boxHeight);
  20255. }, scrollEnv => {
  20256. const constrainedBounds = constrain(box, getBoundsFrom(scrollEnv));
  20257. const constrainedBoundsY = isDockedMode(comp, 'top') ? constrainedBounds.y : constrainedBounds.y + headerHeight;
  20258. return bounds(constrainedBounds.x, constrainedBoundsY, constrainedBounds.width, constrainedBounds.height - headerHeight);
  20259. });
  20260. });
  20261. },
  20262. onShow: () => {
  20263. runOnSinkElement(elem => updateSinkVisibility(elem, true));
  20264. },
  20265. onShown: comp => {
  20266. runOnSinkElement(elem => remove$1(elem, [
  20267. visibility.transitionClass,
  20268. visibility.fadeInClass
  20269. ]));
  20270. focusedElm.get().each(elem => {
  20271. restoreFocus(comp.element, elem);
  20272. focusedElm.clear();
  20273. });
  20274. },
  20275. onHide: comp => {
  20276. findFocusedElem(comp.element, lazySink).fold(focusedElm.clear, focusedElm.set);
  20277. runOnSinkElement(elem => updateSinkVisibility(elem, false));
  20278. },
  20279. onHidden: () => {
  20280. runOnSinkElement(elem => remove$1(elem, [visibility.transitionClass]));
  20281. },
  20282. ...visibility
  20283. },
  20284. lazyViewport: comp => {
  20285. const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
  20286. return optScrollingContext.fold(() => {
  20287. const boundsWithoutOffset = win();
  20288. const offset = getStickyToolbarOffset(editor);
  20289. const top = boundsWithoutOffset.y + (isDockedMode(comp, 'top') ? offset : 0);
  20290. const height = boundsWithoutOffset.height - (isDockedMode(comp, 'bottom') ? offset : 0);
  20291. return {
  20292. bounds: bounds(boundsWithoutOffset.x, top, boundsWithoutOffset.width, height),
  20293. optScrollEnv: Optional.none()
  20294. };
  20295. }, sc => {
  20296. const combinedBounds = getBoundsFrom(sc);
  20297. return {
  20298. bounds: combinedBounds,
  20299. optScrollEnv: Optional.some({
  20300. currentScrollTop: sc.element.dom.scrollTop,
  20301. scrollElmTop: absolute$3(sc.element).top
  20302. })
  20303. };
  20304. });
  20305. },
  20306. modes: [sharedBackstage.header.getDockingMode()],
  20307. onDocked: onDockingSwitch,
  20308. onUndocked: onDockingSwitch
  20309. }),
  20310. ...additionalBehaviours
  20311. ];
  20312. };
  20313. var StickyHeader = /*#__PURE__*/Object.freeze({
  20314. __proto__: null,
  20315. setup: setup$9,
  20316. isDocked: isDocked,
  20317. getBehaviours: getBehaviours
  20318. });
  20319. const renderHeader = spec => {
  20320. const editor = spec.editor;
  20321. const getBehaviours$2 = spec.sticky ? getBehaviours : getBehaviours$1;
  20322. return {
  20323. uid: spec.uid,
  20324. dom: spec.dom,
  20325. components: spec.components,
  20326. behaviours: derive$1(getBehaviours$2(editor, spec.sharedBackstage))
  20327. };
  20328. };
  20329. const groupToolbarButtonSchema = objOf([
  20330. type,
  20331. requiredOf('items', oneOf([
  20332. arrOfObj([
  20333. name$1,
  20334. requiredArrayOf('items', string)
  20335. ]),
  20336. string
  20337. ]))
  20338. ].concat(baseToolbarButtonFields));
  20339. const createGroupToolbarButton = spec => asRaw('GroupToolbarButton', groupToolbarButtonSchema, spec);
  20340. const baseMenuButtonFields = [
  20341. optionString('text'),
  20342. optionString('tooltip'),
  20343. optionString('icon'),
  20344. defaultedOf('search', false, oneOf([
  20345. boolean,
  20346. objOf([optionString('placeholder')])
  20347. ], x => {
  20348. if (isBoolean(x)) {
  20349. return x ? Optional.some({ placeholder: Optional.none() }) : Optional.none();
  20350. } else {
  20351. return Optional.some(x);
  20352. }
  20353. })),
  20354. requiredFunction('fetch'),
  20355. defaultedFunction('onSetup', () => noop)
  20356. ];
  20357. const MenuButtonSchema = objOf([
  20358. type,
  20359. ...baseMenuButtonFields
  20360. ]);
  20361. const createMenuButton = spec => asRaw('menubutton', MenuButtonSchema, spec);
  20362. const splitButtonSchema = objOf([
  20363. type,
  20364. optionalTooltip,
  20365. optionalIcon,
  20366. optionalText,
  20367. optionalSelect,
  20368. fetch$1,
  20369. onSetup,
  20370. defaultedStringEnum('presets', 'normal', [
  20371. 'normal',
  20372. 'color',
  20373. 'listpreview'
  20374. ]),
  20375. defaultedColumns(1),
  20376. onAction,
  20377. onItemAction
  20378. ]);
  20379. const createSplitButton = spec => asRaw('SplitButton', splitButtonSchema, spec);
  20380. const factory$d = (detail, spec) => {
  20381. const setMenus = (comp, menus) => {
  20382. const newMenus = map$2(menus, m => {
  20383. const buttonSpec = {
  20384. type: 'menubutton',
  20385. text: m.text,
  20386. fetch: callback => {
  20387. callback(m.getItems());
  20388. }
  20389. };
  20390. const internal = createMenuButton(buttonSpec).mapError(errInfo => formatError(errInfo)).getOrDie();
  20391. return renderMenuButton(internal, 'tox-mbtn', spec.backstage, Optional.some('menuitem'));
  20392. });
  20393. Replacing.set(comp, newMenus);
  20394. };
  20395. const apis = {
  20396. focus: Keying.focusIn,
  20397. setMenus
  20398. };
  20399. return {
  20400. uid: detail.uid,
  20401. dom: detail.dom,
  20402. components: [],
  20403. behaviours: derive$1([
  20404. Replacing.config({}),
  20405. config('menubar-events', [
  20406. runOnAttached(component => {
  20407. detail.onSetup(component);
  20408. }),
  20409. run$1(mouseover(), (comp, se) => {
  20410. descendant(comp.element, '.' + 'tox-mbtn--active').each(activeButton => {
  20411. closest$1(se.event.target, '.' + 'tox-mbtn').each(hoveredButton => {
  20412. if (!eq(activeButton, hoveredButton)) {
  20413. comp.getSystem().getByDom(activeButton).each(activeComp => {
  20414. comp.getSystem().getByDom(hoveredButton).each(hoveredComp => {
  20415. Dropdown.expand(hoveredComp);
  20416. Dropdown.close(activeComp);
  20417. Focusing.focus(hoveredComp);
  20418. });
  20419. });
  20420. }
  20421. });
  20422. });
  20423. }),
  20424. run$1(focusShifted(), (comp, se) => {
  20425. se.event.prevFocus.bind(prev => comp.getSystem().getByDom(prev).toOptional()).each(prev => {
  20426. se.event.newFocus.bind(nu => comp.getSystem().getByDom(nu).toOptional()).each(nu => {
  20427. if (Dropdown.isOpen(prev)) {
  20428. Dropdown.expand(nu);
  20429. Dropdown.close(prev);
  20430. }
  20431. });
  20432. });
  20433. })
  20434. ]),
  20435. Keying.config({
  20436. mode: 'flow',
  20437. selector: '.' + 'tox-mbtn',
  20438. onEscape: comp => {
  20439. detail.onEscape(comp);
  20440. return Optional.some(true);
  20441. }
  20442. }),
  20443. Tabstopping.config({})
  20444. ]),
  20445. apis,
  20446. domModification: { attributes: { role: 'menubar' } }
  20447. };
  20448. };
  20449. var SilverMenubar = single({
  20450. factory: factory$d,
  20451. name: 'silver.Menubar',
  20452. configFields: [
  20453. required$1('dom'),
  20454. required$1('uid'),
  20455. required$1('onEscape'),
  20456. required$1('backstage'),
  20457. defaulted('onSetup', noop)
  20458. ],
  20459. apis: {
  20460. focus: (apis, comp) => {
  20461. apis.focus(comp);
  20462. },
  20463. setMenus: (apis, comp, menus) => {
  20464. apis.setMenus(comp, menus);
  20465. }
  20466. }
  20467. });
  20468. const promotionMessage = '\u26A1\ufe0fUpgrade';
  20469. const promotionLink = 'https://www.tiny.cloud/tinymce-self-hosted-premium-features/?utm_campaign=self_hosted_upgrade_promo&utm_source=tiny&utm_medium=referral';
  20470. const renderPromotion = spec => {
  20471. return {
  20472. uid: spec.uid,
  20473. dom: spec.dom,
  20474. components: [{
  20475. dom: {
  20476. tag: 'a',
  20477. attributes: {
  20478. 'href': promotionLink,
  20479. 'rel': 'noopener',
  20480. 'target': '_blank',
  20481. 'aria-hidden': 'true'
  20482. },
  20483. classes: ['tox-promotion-link'],
  20484. innerHtml: promotionMessage
  20485. }
  20486. }]
  20487. };
  20488. };
  20489. const owner = 'container';
  20490. const schema$d = [field('slotBehaviours', [])];
  20491. const getPartName = name => '<alloy.field.' + name + '>';
  20492. const sketch = sSpec => {
  20493. const parts = (() => {
  20494. const record = [];
  20495. const slot = (name, config) => {
  20496. record.push(name);
  20497. return generateOne$1(owner, getPartName(name), config);
  20498. };
  20499. return {
  20500. slot,
  20501. record: constant$1(record)
  20502. };
  20503. })();
  20504. const spec = sSpec(parts);
  20505. const partNames = parts.record();
  20506. const fieldParts = map$2(partNames, n => required({
  20507. name: n,
  20508. pname: getPartName(n)
  20509. }));
  20510. return composite$1(owner, schema$d, fieldParts, make$1, spec);
  20511. };
  20512. const make$1 = (detail, components) => {
  20513. const getSlotNames = _ => getAllPartNames(detail);
  20514. const getSlot = (container, key) => getPart(container, detail, key);
  20515. const onSlot = (f, def) => (container, key) => getPart(container, detail, key).map(slot => f(slot, key)).getOr(def);
  20516. const onSlots = f => (container, keys) => {
  20517. each$1(keys, key => f(container, key));
  20518. };
  20519. const doShowing = (comp, _key) => get$f(comp.element, 'aria-hidden') !== 'true';
  20520. const doShow = (comp, key) => {
  20521. if (!doShowing(comp)) {
  20522. const element = comp.element;
  20523. remove$6(element, 'display');
  20524. remove$7(element, 'aria-hidden');
  20525. emitWith(comp, slotVisibility(), {
  20526. name: key,
  20527. visible: true
  20528. });
  20529. }
  20530. };
  20531. const doHide = (comp, key) => {
  20532. if (doShowing(comp)) {
  20533. const element = comp.element;
  20534. set$8(element, 'display', 'none');
  20535. set$9(element, 'aria-hidden', 'true');
  20536. emitWith(comp, slotVisibility(), {
  20537. name: key,
  20538. visible: false
  20539. });
  20540. }
  20541. };
  20542. const isShowing = onSlot(doShowing, false);
  20543. const hideSlot = onSlot(doHide);
  20544. const hideSlots = onSlots(hideSlot);
  20545. const hideAllSlots = container => hideSlots(container, getSlotNames());
  20546. const showSlot = onSlot(doShow);
  20547. const apis = {
  20548. getSlotNames,
  20549. getSlot,
  20550. isShowing,
  20551. hideSlot,
  20552. hideAllSlots,
  20553. showSlot
  20554. };
  20555. return {
  20556. uid: detail.uid,
  20557. dom: detail.dom,
  20558. components,
  20559. behaviours: get$3(detail.slotBehaviours),
  20560. apis
  20561. };
  20562. };
  20563. const slotApis = map$1({
  20564. getSlotNames: (apis, c) => apis.getSlotNames(c),
  20565. getSlot: (apis, c, key) => apis.getSlot(c, key),
  20566. isShowing: (apis, c, key) => apis.isShowing(c, key),
  20567. hideSlot: (apis, c, key) => apis.hideSlot(c, key),
  20568. hideAllSlots: (apis, c) => apis.hideAllSlots(c),
  20569. showSlot: (apis, c, key) => apis.showSlot(c, key)
  20570. }, value => makeApi(value));
  20571. const SlotContainer = {
  20572. ...slotApis,
  20573. ...{ sketch }
  20574. };
  20575. const sidebarSchema = objOf([
  20576. optionalIcon,
  20577. optionalTooltip,
  20578. defaultedFunction('onShow', noop),
  20579. defaultedFunction('onHide', noop),
  20580. onSetup
  20581. ]);
  20582. const createSidebar = spec => asRaw('sidebar', sidebarSchema, spec);
  20583. const setup$8 = editor => {
  20584. const {sidebars} = editor.ui.registry.getAll();
  20585. each$1(keys(sidebars), name => {
  20586. const spec = sidebars[name];
  20587. const isActive = () => is$1(Optional.from(editor.queryCommandValue('ToggleSidebar')), name);
  20588. editor.ui.registry.addToggleButton(name, {
  20589. icon: spec.icon,
  20590. tooltip: spec.tooltip,
  20591. onAction: buttonApi => {
  20592. editor.execCommand('ToggleSidebar', false, name);
  20593. buttonApi.setActive(isActive());
  20594. },
  20595. onSetup: buttonApi => {
  20596. buttonApi.setActive(isActive());
  20597. const handleToggle = () => buttonApi.setActive(isActive());
  20598. editor.on('ToggleSidebar', handleToggle);
  20599. return () => {
  20600. editor.off('ToggleSidebar', handleToggle);
  20601. };
  20602. }
  20603. });
  20604. });
  20605. };
  20606. const getApi = comp => ({ element: () => comp.element.dom });
  20607. const makePanels = (parts, panelConfigs) => {
  20608. const specs = map$2(keys(panelConfigs), name => {
  20609. const spec = panelConfigs[name];
  20610. const bridged = getOrDie(createSidebar(spec));
  20611. return {
  20612. name,
  20613. getApi,
  20614. onSetup: bridged.onSetup,
  20615. onShow: bridged.onShow,
  20616. onHide: bridged.onHide
  20617. };
  20618. });
  20619. return map$2(specs, spec => {
  20620. const editorOffCell = Cell(noop);
  20621. return parts.slot(spec.name, {
  20622. dom: {
  20623. tag: 'div',
  20624. classes: ['tox-sidebar__pane']
  20625. },
  20626. behaviours: SimpleBehaviours.unnamedEvents([
  20627. onControlAttached(spec, editorOffCell),
  20628. onControlDetached(spec, editorOffCell),
  20629. run$1(slotVisibility(), (sidepanel, se) => {
  20630. const data = se.event;
  20631. const optSidePanelSpec = find$5(specs, config => config.name === data.name);
  20632. optSidePanelSpec.each(sidePanelSpec => {
  20633. const handler = data.visible ? sidePanelSpec.onShow : sidePanelSpec.onHide;
  20634. handler(sidePanelSpec.getApi(sidepanel));
  20635. });
  20636. })
  20637. ])
  20638. });
  20639. });
  20640. };
  20641. const makeSidebar = panelConfigs => SlotContainer.sketch(parts => ({
  20642. dom: {
  20643. tag: 'div',
  20644. classes: ['tox-sidebar__pane-container']
  20645. },
  20646. components: makePanels(parts, panelConfigs),
  20647. slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
  20648. }));
  20649. const setSidebar = (sidebar, panelConfigs, showSidebar) => {
  20650. const optSlider = Composing.getCurrent(sidebar);
  20651. optSlider.each(slider => {
  20652. Replacing.set(slider, [makeSidebar(panelConfigs)]);
  20653. const configKey = showSidebar === null || showSidebar === void 0 ? void 0 : showSidebar.toLowerCase();
  20654. if (isString(configKey) && has$2(panelConfigs, configKey)) {
  20655. Composing.getCurrent(slider).each(slotContainer => {
  20656. SlotContainer.showSlot(slotContainer, configKey);
  20657. Sliding.immediateGrow(slider);
  20658. remove$6(slider.element, 'width');
  20659. updateSidebarRoleOnToggle(sidebar.element, 'region');
  20660. });
  20661. }
  20662. });
  20663. };
  20664. const updateSidebarRoleOnToggle = (sidebar, sidebarState) => {
  20665. set$9(sidebar, 'role', sidebarState);
  20666. };
  20667. const toggleSidebar = (sidebar, name) => {
  20668. const optSlider = Composing.getCurrent(sidebar);
  20669. optSlider.each(slider => {
  20670. const optSlotContainer = Composing.getCurrent(slider);
  20671. optSlotContainer.each(slotContainer => {
  20672. if (Sliding.hasGrown(slider)) {
  20673. if (SlotContainer.isShowing(slotContainer, name)) {
  20674. Sliding.shrink(slider);
  20675. updateSidebarRoleOnToggle(sidebar.element, 'presentation');
  20676. } else {
  20677. SlotContainer.hideAllSlots(slotContainer);
  20678. SlotContainer.showSlot(slotContainer, name);
  20679. updateSidebarRoleOnToggle(sidebar.element, 'region');
  20680. }
  20681. } else {
  20682. SlotContainer.hideAllSlots(slotContainer);
  20683. SlotContainer.showSlot(slotContainer, name);
  20684. Sliding.grow(slider);
  20685. updateSidebarRoleOnToggle(sidebar.element, 'region');
  20686. }
  20687. });
  20688. });
  20689. };
  20690. const whichSidebar = sidebar => {
  20691. const optSlider = Composing.getCurrent(sidebar);
  20692. return optSlider.bind(slider => {
  20693. const sidebarOpen = Sliding.isGrowing(slider) || Sliding.hasGrown(slider);
  20694. if (sidebarOpen) {
  20695. const optSlotContainer = Composing.getCurrent(slider);
  20696. return optSlotContainer.bind(slotContainer => find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name)));
  20697. } else {
  20698. return Optional.none();
  20699. }
  20700. });
  20701. };
  20702. const fixSize = generate$6('FixSizeEvent');
  20703. const autoSize = generate$6('AutoSizeEvent');
  20704. const renderSidebar = spec => ({
  20705. uid: spec.uid,
  20706. dom: {
  20707. tag: 'div',
  20708. classes: ['tox-sidebar'],
  20709. attributes: { role: 'presentation' }
  20710. },
  20711. components: [{
  20712. dom: {
  20713. tag: 'div',
  20714. classes: ['tox-sidebar__slider']
  20715. },
  20716. components: [],
  20717. behaviours: derive$1([
  20718. Tabstopping.config({}),
  20719. Focusing.config({}),
  20720. Sliding.config({
  20721. dimension: { property: 'width' },
  20722. closedClass: 'tox-sidebar--sliding-closed',
  20723. openClass: 'tox-sidebar--sliding-open',
  20724. shrinkingClass: 'tox-sidebar--sliding-shrinking',
  20725. growingClass: 'tox-sidebar--sliding-growing',
  20726. onShrunk: slider => {
  20727. const optSlotContainer = Composing.getCurrent(slider);
  20728. optSlotContainer.each(SlotContainer.hideAllSlots);
  20729. emit(slider, autoSize);
  20730. },
  20731. onGrown: slider => {
  20732. emit(slider, autoSize);
  20733. },
  20734. onStartGrow: slider => {
  20735. emitWith(slider, fixSize, { width: getRaw(slider.element, 'width').getOr('') });
  20736. },
  20737. onStartShrink: slider => {
  20738. emitWith(slider, fixSize, { width: get$c(slider.element) + 'px' });
  20739. }
  20740. }),
  20741. Replacing.config({}),
  20742. Composing.config({
  20743. find: comp => {
  20744. const children = Replacing.contents(comp);
  20745. return head(children);
  20746. }
  20747. })
  20748. ])
  20749. }],
  20750. behaviours: derive$1([
  20751. ComposingConfigs.childAt(0),
  20752. config('sidebar-sliding-events', [
  20753. run$1(fixSize, (comp, se) => {
  20754. set$8(comp.element, 'width', se.event.width);
  20755. }),
  20756. run$1(autoSize, (comp, _se) => {
  20757. remove$6(comp.element, 'width');
  20758. })
  20759. ])
  20760. ])
  20761. });
  20762. const block = (component, config, state, getBusySpec) => {
  20763. set$9(component.element, 'aria-busy', true);
  20764. const root = config.getRoot(component).getOr(component);
  20765. const blockerBehaviours = derive$1([
  20766. Keying.config({
  20767. mode: 'special',
  20768. onTab: () => Optional.some(true),
  20769. onShiftTab: () => Optional.some(true)
  20770. }),
  20771. Focusing.config({})
  20772. ]);
  20773. const blockSpec = getBusySpec(root, blockerBehaviours);
  20774. const blocker = root.getSystem().build(blockSpec);
  20775. Replacing.append(root, premade(blocker));
  20776. if (blocker.hasConfigured(Keying) && config.focus) {
  20777. Keying.focusIn(blocker);
  20778. }
  20779. if (!state.isBlocked()) {
  20780. config.onBlock(component);
  20781. }
  20782. state.blockWith(() => Replacing.remove(root, blocker));
  20783. };
  20784. const unblock = (component, config, state) => {
  20785. remove$7(component.element, 'aria-busy');
  20786. if (state.isBlocked()) {
  20787. config.onUnblock(component);
  20788. }
  20789. state.clear();
  20790. };
  20791. const isBlocked = (component, blockingConfig, blockingState) => blockingState.isBlocked();
  20792. var BlockingApis = /*#__PURE__*/Object.freeze({
  20793. __proto__: null,
  20794. block: block,
  20795. unblock: unblock,
  20796. isBlocked: isBlocked
  20797. });
  20798. var BlockingSchema = [
  20799. defaultedFunction('getRoot', Optional.none),
  20800. defaultedBoolean('focus', true),
  20801. onHandler('onBlock'),
  20802. onHandler('onUnblock')
  20803. ];
  20804. const init$4 = () => {
  20805. const blocker = destroyable();
  20806. const blockWith = destroy => {
  20807. blocker.set({ destroy });
  20808. };
  20809. return nu$8({
  20810. readState: blocker.isSet,
  20811. blockWith,
  20812. clear: blocker.clear,
  20813. isBlocked: blocker.isSet
  20814. });
  20815. };
  20816. var BlockingState = /*#__PURE__*/Object.freeze({
  20817. __proto__: null,
  20818. init: init$4
  20819. });
  20820. const Blocking = create$4({
  20821. fields: BlockingSchema,
  20822. name: 'blocking',
  20823. apis: BlockingApis,
  20824. state: BlockingState
  20825. });
  20826. const getBusySpec$1 = providerBackstage => (_root, _behaviours) => ({
  20827. dom: {
  20828. tag: 'div',
  20829. attributes: {
  20830. 'aria-label': providerBackstage.translate('Loading...'),
  20831. 'tabindex': '0'
  20832. },
  20833. classes: ['tox-throbber__busy-spinner']
  20834. },
  20835. components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  20836. });
  20837. const focusBusyComponent = throbber => Composing.getCurrent(throbber).each(comp => focus$3(comp.element, true));
  20838. const toggleEditorTabIndex = (editor, state) => {
  20839. const tabIndexAttr = 'tabindex';
  20840. const dataTabIndexAttr = `data-mce-${ tabIndexAttr }`;
  20841. Optional.from(editor.iframeElement).map(SugarElement.fromDom).each(iframe => {
  20842. if (state) {
  20843. getOpt(iframe, tabIndexAttr).each(tabIndex => set$9(iframe, dataTabIndexAttr, tabIndex));
  20844. set$9(iframe, tabIndexAttr, -1);
  20845. } else {
  20846. remove$7(iframe, tabIndexAttr);
  20847. getOpt(iframe, dataTabIndexAttr).each(tabIndex => {
  20848. set$9(iframe, tabIndexAttr, tabIndex);
  20849. remove$7(iframe, dataTabIndexAttr);
  20850. });
  20851. }
  20852. });
  20853. };
  20854. const toggleThrobber = (editor, comp, state, providerBackstage) => {
  20855. const element = comp.element;
  20856. toggleEditorTabIndex(editor, state);
  20857. if (state) {
  20858. Blocking.block(comp, getBusySpec$1(providerBackstage));
  20859. remove$6(element, 'display');
  20860. remove$7(element, 'aria-hidden');
  20861. if (editor.hasFocus()) {
  20862. focusBusyComponent(comp);
  20863. }
  20864. } else {
  20865. const throbberFocus = Composing.getCurrent(comp).exists(busyComp => hasFocus(busyComp.element));
  20866. Blocking.unblock(comp);
  20867. set$8(element, 'display', 'none');
  20868. set$9(element, 'aria-hidden', 'true');
  20869. if (throbberFocus) {
  20870. editor.focus();
  20871. }
  20872. }
  20873. };
  20874. const renderThrobber = spec => ({
  20875. uid: spec.uid,
  20876. dom: {
  20877. tag: 'div',
  20878. attributes: { 'aria-hidden': 'true' },
  20879. classes: ['tox-throbber'],
  20880. styles: { display: 'none' }
  20881. },
  20882. behaviours: derive$1([
  20883. Replacing.config({}),
  20884. Blocking.config({ focus: false }),
  20885. Composing.config({ find: comp => head(comp.components()) })
  20886. ]),
  20887. components: []
  20888. });
  20889. const isFocusEvent = event => event.type === 'focusin';
  20890. const isPasteBinTarget = event => {
  20891. if (isFocusEvent(event)) {
  20892. const node = event.composed ? head(event.composedPath()) : Optional.from(event.target);
  20893. return node.map(SugarElement.fromDom).filter(isElement$1).exists(targetElm => has(targetElm, 'mce-pastebin'));
  20894. } else {
  20895. return false;
  20896. }
  20897. };
  20898. const setup$7 = (editor, lazyThrobber, sharedBackstage) => {
  20899. const throbberState = Cell(false);
  20900. const timer = value$2();
  20901. const stealFocus = e => {
  20902. if (throbberState.get() && !isPasteBinTarget(e)) {
  20903. e.preventDefault();
  20904. focusBusyComponent(lazyThrobber());
  20905. editor.editorManager.setActive(editor);
  20906. }
  20907. };
  20908. if (!editor.inline) {
  20909. editor.on('PreInit', () => {
  20910. editor.dom.bind(editor.getWin(), 'focusin', stealFocus);
  20911. editor.on('BeforeExecCommand', e => {
  20912. if (e.command.toLowerCase() === 'mcefocus' && e.value !== true) {
  20913. stealFocus(e);
  20914. }
  20915. });
  20916. });
  20917. }
  20918. const toggle = state => {
  20919. if (state !== throbberState.get()) {
  20920. throbberState.set(state);
  20921. toggleThrobber(editor, lazyThrobber(), state, sharedBackstage.providers);
  20922. fireAfterProgressState(editor, state);
  20923. }
  20924. };
  20925. editor.on('ProgressState', e => {
  20926. timer.on(clearTimeout);
  20927. if (isNumber(e.time)) {
  20928. const timerId = global$9.setEditorTimeout(editor, () => toggle(e.state), e.time);
  20929. timer.set(timerId);
  20930. } else {
  20931. toggle(e.state);
  20932. timer.clear();
  20933. }
  20934. });
  20935. };
  20936. const generate$1 = (xs, f) => {
  20937. const init = {
  20938. len: 0,
  20939. list: []
  20940. };
  20941. const r = foldl(xs, (b, a) => {
  20942. const value = f(a, b.len);
  20943. return value.fold(constant$1(b), v => ({
  20944. len: v.finish,
  20945. list: b.list.concat([v])
  20946. }));
  20947. }, init);
  20948. return r.list;
  20949. };
  20950. const output = (within, extra, withinWidth) => ({
  20951. within,
  20952. extra,
  20953. withinWidth
  20954. });
  20955. const apportion = (units, total, len) => {
  20956. const parray = generate$1(units, (unit, current) => {
  20957. const width = len(unit);
  20958. return Optional.some({
  20959. element: unit,
  20960. start: current,
  20961. finish: current + width,
  20962. width
  20963. });
  20964. });
  20965. const within = filter$2(parray, unit => unit.finish <= total);
  20966. const withinWidth = foldr(within, (acc, el) => acc + el.width, 0);
  20967. const extra = parray.slice(within.length);
  20968. return {
  20969. within,
  20970. extra,
  20971. withinWidth
  20972. };
  20973. };
  20974. const toUnit = parray => map$2(parray, unit => unit.element);
  20975. const fitLast = (within, extra, withinWidth) => {
  20976. const fits = toUnit(within.concat(extra));
  20977. return output(fits, [], withinWidth);
  20978. };
  20979. const overflow = (within, extra, overflower, withinWidth) => {
  20980. const fits = toUnit(within).concat([overflower]);
  20981. return output(fits, toUnit(extra), withinWidth);
  20982. };
  20983. const fitAll = (within, extra, withinWidth) => output(toUnit(within), [], withinWidth);
  20984. const tryFit = (total, units, len) => {
  20985. const divide = apportion(units, total, len);
  20986. return divide.extra.length === 0 ? Optional.some(divide) : Optional.none();
  20987. };
  20988. const partition = (total, units, len, overflower) => {
  20989. const divide = tryFit(total, units, len).getOrThunk(() => apportion(units, total - len(overflower), len));
  20990. const within = divide.within;
  20991. const extra = divide.extra;
  20992. const withinWidth = divide.withinWidth;
  20993. if (extra.length === 1 && extra[0].width <= len(overflower)) {
  20994. return fitLast(within, extra, withinWidth);
  20995. } else if (extra.length >= 1) {
  20996. return overflow(within, extra, overflower, withinWidth);
  20997. } else {
  20998. return fitAll(within, extra, withinWidth);
  20999. }
  21000. };
  21001. const setGroups$1 = (toolbar, storedGroups) => {
  21002. const bGroups = map$2(storedGroups, g => premade(g));
  21003. Toolbar.setGroups(toolbar, bGroups);
  21004. };
  21005. const findFocusedComp = comps => findMap(comps, comp => search(comp.element).bind(focusedElm => comp.getSystem().getByDom(focusedElm).toOptional()));
  21006. const refresh$2 = (toolbar, detail, setOverflow) => {
  21007. const builtGroups = detail.builtGroups.get();
  21008. if (builtGroups.length === 0) {
  21009. return;
  21010. }
  21011. const primary = getPartOrDie(toolbar, detail, 'primary');
  21012. const overflowGroup = Coupling.getCoupled(toolbar, 'overflowGroup');
  21013. set$8(primary.element, 'visibility', 'hidden');
  21014. const groups = builtGroups.concat([overflowGroup]);
  21015. const focusedComp = findFocusedComp(groups);
  21016. setOverflow([]);
  21017. setGroups$1(primary, groups);
  21018. const availableWidth = get$c(primary.element);
  21019. const overflows = partition(availableWidth, detail.builtGroups.get(), comp => get$c(comp.element), overflowGroup);
  21020. if (overflows.extra.length === 0) {
  21021. Replacing.remove(primary, overflowGroup);
  21022. setOverflow([]);
  21023. } else {
  21024. setGroups$1(primary, overflows.within);
  21025. setOverflow(overflows.extra);
  21026. }
  21027. remove$6(primary.element, 'visibility');
  21028. reflow(primary.element);
  21029. focusedComp.each(Focusing.focus);
  21030. };
  21031. const schema$c = constant$1([
  21032. field('splitToolbarBehaviours', [Coupling]),
  21033. customField('builtGroups', () => Cell([]))
  21034. ]);
  21035. const schema$b = constant$1([
  21036. markers$1(['overflowToggledClass']),
  21037. optionFunction('getOverflowBounds'),
  21038. required$1('lazySink'),
  21039. customField('overflowGroups', () => Cell([])),
  21040. onHandler('onOpened'),
  21041. onHandler('onClosed')
  21042. ].concat(schema$c()));
  21043. const parts$7 = constant$1([
  21044. required({
  21045. factory: Toolbar,
  21046. schema: schema$e(),
  21047. name: 'primary'
  21048. }),
  21049. external({
  21050. schema: schema$e(),
  21051. name: 'overflow'
  21052. }),
  21053. external({ name: 'overflow-button' }),
  21054. external({ name: 'overflow-group' })
  21055. ]);
  21056. const expandable = constant$1((element, available) => {
  21057. setMax(element, Math.floor(available));
  21058. });
  21059. const schema$a = constant$1([
  21060. markers$1(['toggledClass']),
  21061. required$1('lazySink'),
  21062. requiredFunction('fetch'),
  21063. optionFunction('getBounds'),
  21064. optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
  21065. schema$y(),
  21066. onHandler('onToggled')
  21067. ]);
  21068. const parts$6 = constant$1([
  21069. external({
  21070. name: 'button',
  21071. overrides: detail => ({
  21072. dom: { attributes: { 'aria-haspopup': 'true' } },
  21073. buttonBehaviours: derive$1([Toggling.config({
  21074. toggleClass: detail.markers.toggledClass,
  21075. aria: { mode: 'expanded' },
  21076. toggleOnExecute: false,
  21077. onToggled: detail.onToggled
  21078. })])
  21079. })
  21080. }),
  21081. external({
  21082. factory: Toolbar,
  21083. schema: schema$e(),
  21084. name: 'toolbar',
  21085. overrides: detail => {
  21086. return {
  21087. toolbarBehaviours: derive$1([Keying.config({
  21088. mode: 'cyclic',
  21089. onEscape: comp => {
  21090. getPart(comp, detail, 'button').each(Focusing.focus);
  21091. return Optional.none();
  21092. }
  21093. })])
  21094. };
  21095. }
  21096. })
  21097. ]);
  21098. const shouldSkipFocus = value$2();
  21099. const toggleWithoutFocusing = (button, externals) => {
  21100. shouldSkipFocus.set(true);
  21101. toggle(button, externals);
  21102. shouldSkipFocus.clear();
  21103. };
  21104. const toggle = (button, externals) => {
  21105. const toolbarSandbox = Coupling.getCoupled(button, 'toolbarSandbox');
  21106. if (Sandboxing.isOpen(toolbarSandbox)) {
  21107. Sandboxing.close(toolbarSandbox);
  21108. } else {
  21109. Sandboxing.open(toolbarSandbox, externals.toolbar());
  21110. }
  21111. };
  21112. const position = (button, toolbar, detail, layouts) => {
  21113. const bounds = detail.getBounds.map(bounder => bounder());
  21114. const sink = detail.lazySink(button).getOrDie();
  21115. Positioning.positionWithinBounds(sink, toolbar, {
  21116. anchor: {
  21117. type: 'hotspot',
  21118. hotspot: button,
  21119. layouts,
  21120. overrides: { maxWidthFunction: expandable() }
  21121. }
  21122. }, bounds);
  21123. };
  21124. const setGroups = (button, toolbar, detail, layouts, groups) => {
  21125. Toolbar.setGroups(toolbar, groups);
  21126. position(button, toolbar, detail, layouts);
  21127. Toggling.on(button);
  21128. };
  21129. const makeSandbox = (button, spec, detail) => {
  21130. const ariaControls = manager();
  21131. const onOpen = (sandbox, toolbar) => {
  21132. const skipFocus = shouldSkipFocus.get().getOr(false);
  21133. detail.fetch().get(groups => {
  21134. setGroups(button, toolbar, detail, spec.layouts, groups);
  21135. ariaControls.link(button.element);
  21136. if (!skipFocus) {
  21137. Keying.focusIn(toolbar);
  21138. }
  21139. });
  21140. };
  21141. const onClose = () => {
  21142. Toggling.off(button);
  21143. if (!shouldSkipFocus.get().getOr(false)) {
  21144. Focusing.focus(button);
  21145. }
  21146. ariaControls.unlink(button.element);
  21147. };
  21148. return {
  21149. dom: {
  21150. tag: 'div',
  21151. attributes: { id: ariaControls.id }
  21152. },
  21153. behaviours: derive$1([
  21154. Keying.config({
  21155. mode: 'special',
  21156. onEscape: comp => {
  21157. Sandboxing.close(comp);
  21158. return Optional.some(true);
  21159. }
  21160. }),
  21161. Sandboxing.config({
  21162. onOpen,
  21163. onClose,
  21164. isPartOf: (container, data, queryElem) => {
  21165. return isPartOf$1(data, queryElem) || isPartOf$1(button, queryElem);
  21166. },
  21167. getAttachPoint: () => {
  21168. return detail.lazySink(button).getOrDie();
  21169. }
  21170. }),
  21171. Receiving.config({
  21172. channels: {
  21173. ...receivingChannel$1({
  21174. isExtraPart: never,
  21175. ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
  21176. }),
  21177. ...receivingChannel({
  21178. doReposition: () => {
  21179. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  21180. position(button, toolbar, detail, spec.layouts);
  21181. });
  21182. }
  21183. })
  21184. }
  21185. })
  21186. ])
  21187. };
  21188. };
  21189. const factory$c = (detail, components, spec, externals) => ({
  21190. ...Button.sketch({
  21191. ...externals.button(),
  21192. action: button => {
  21193. toggle(button, externals);
  21194. },
  21195. buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [Coupling.config({
  21196. others: {
  21197. toolbarSandbox: button => {
  21198. return makeSandbox(button, spec, detail);
  21199. }
  21200. }
  21201. })])
  21202. }),
  21203. apis: {
  21204. setGroups: (button, groups) => {
  21205. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  21206. setGroups(button, toolbar, detail, spec.layouts, groups);
  21207. });
  21208. },
  21209. reposition: button => {
  21210. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  21211. position(button, toolbar, detail, spec.layouts);
  21212. });
  21213. },
  21214. toggle: button => {
  21215. toggle(button, externals);
  21216. },
  21217. toggleWithoutFocusing: button => {
  21218. toggleWithoutFocusing(button, externals);
  21219. },
  21220. getToolbar: button => {
  21221. return Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox'));
  21222. },
  21223. isOpen: button => {
  21224. return Sandboxing.isOpen(Coupling.getCoupled(button, 'toolbarSandbox'));
  21225. }
  21226. }
  21227. });
  21228. const FloatingToolbarButton = composite({
  21229. name: 'FloatingToolbarButton',
  21230. factory: factory$c,
  21231. configFields: schema$a(),
  21232. partFields: parts$6(),
  21233. apis: {
  21234. setGroups: (apis, button, groups) => {
  21235. apis.setGroups(button, groups);
  21236. },
  21237. reposition: (apis, button) => {
  21238. apis.reposition(button);
  21239. },
  21240. toggle: (apis, button) => {
  21241. apis.toggle(button);
  21242. },
  21243. toggleWithoutFocusing: (apis, button) => {
  21244. apis.toggleWithoutFocusing(button);
  21245. },
  21246. getToolbar: (apis, button) => apis.getToolbar(button),
  21247. isOpen: (apis, button) => apis.isOpen(button)
  21248. }
  21249. });
  21250. const schema$9 = constant$1([
  21251. required$1('items'),
  21252. markers$1(['itemSelector']),
  21253. field('tgroupBehaviours', [Keying])
  21254. ]);
  21255. const parts$5 = constant$1([group({
  21256. name: 'items',
  21257. unit: 'item'
  21258. })]);
  21259. const factory$b = (detail, components, _spec, _externals) => ({
  21260. uid: detail.uid,
  21261. dom: detail.dom,
  21262. components,
  21263. behaviours: augment(detail.tgroupBehaviours, [Keying.config({
  21264. mode: 'flow',
  21265. selector: detail.markers.itemSelector
  21266. })]),
  21267. domModification: { attributes: { role: 'toolbar' } }
  21268. });
  21269. const ToolbarGroup = composite({
  21270. name: 'ToolbarGroup',
  21271. configFields: schema$9(),
  21272. partFields: parts$5(),
  21273. factory: factory$b
  21274. });
  21275. const buildGroups = comps => map$2(comps, g => premade(g));
  21276. const refresh$1 = (toolbar, memFloatingToolbarButton, detail) => {
  21277. refresh$2(toolbar, detail, overflowGroups => {
  21278. detail.overflowGroups.set(overflowGroups);
  21279. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  21280. FloatingToolbarButton.setGroups(floatingToolbarButton, buildGroups(overflowGroups));
  21281. });
  21282. });
  21283. };
  21284. const factory$a = (detail, components, spec, externals) => {
  21285. const memFloatingToolbarButton = record(FloatingToolbarButton.sketch({
  21286. fetch: () => Future.nu(resolve => {
  21287. resolve(buildGroups(detail.overflowGroups.get()));
  21288. }),
  21289. layouts: {
  21290. onLtr: () => [
  21291. southwest$2,
  21292. southeast$2
  21293. ],
  21294. onRtl: () => [
  21295. southeast$2,
  21296. southwest$2
  21297. ],
  21298. onBottomLtr: () => [
  21299. northwest$2,
  21300. northeast$2
  21301. ],
  21302. onBottomRtl: () => [
  21303. northeast$2,
  21304. northwest$2
  21305. ]
  21306. },
  21307. getBounds: spec.getOverflowBounds,
  21308. lazySink: detail.lazySink,
  21309. fireDismissalEventInstead: {},
  21310. markers: { toggledClass: detail.markers.overflowToggledClass },
  21311. parts: {
  21312. button: externals['overflow-button'](),
  21313. toolbar: externals.overflow()
  21314. },
  21315. onToggled: (comp, state) => detail[state ? 'onOpened' : 'onClosed'](comp)
  21316. }));
  21317. return {
  21318. uid: detail.uid,
  21319. dom: detail.dom,
  21320. components,
  21321. behaviours: augment(detail.splitToolbarBehaviours, [Coupling.config({
  21322. others: {
  21323. overflowGroup: () => {
  21324. return ToolbarGroup.sketch({
  21325. ...externals['overflow-group'](),
  21326. items: [memFloatingToolbarButton.asSpec()]
  21327. });
  21328. }
  21329. }
  21330. })]),
  21331. apis: {
  21332. setGroups: (toolbar, groups) => {
  21333. detail.builtGroups.set(map$2(groups, toolbar.getSystem().build));
  21334. refresh$1(toolbar, memFloatingToolbarButton, detail);
  21335. },
  21336. refresh: toolbar => refresh$1(toolbar, memFloatingToolbarButton, detail),
  21337. toggle: toolbar => {
  21338. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  21339. FloatingToolbarButton.toggle(floatingToolbarButton);
  21340. });
  21341. },
  21342. toggleWithoutFocusing: toolbar => {
  21343. memFloatingToolbarButton.getOpt(toolbar).each(FloatingToolbarButton.toggleWithoutFocusing);
  21344. },
  21345. isOpen: toolbar => memFloatingToolbarButton.getOpt(toolbar).map(FloatingToolbarButton.isOpen).getOr(false),
  21346. reposition: toolbar => {
  21347. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  21348. FloatingToolbarButton.reposition(floatingToolbarButton);
  21349. });
  21350. },
  21351. getOverflow: toolbar => memFloatingToolbarButton.getOpt(toolbar).bind(FloatingToolbarButton.getToolbar)
  21352. },
  21353. domModification: { attributes: { role: 'group' } }
  21354. };
  21355. };
  21356. const SplitFloatingToolbar = composite({
  21357. name: 'SplitFloatingToolbar',
  21358. configFields: schema$b(),
  21359. partFields: parts$7(),
  21360. factory: factory$a,
  21361. apis: {
  21362. setGroups: (apis, toolbar, groups) => {
  21363. apis.setGroups(toolbar, groups);
  21364. },
  21365. refresh: (apis, toolbar) => {
  21366. apis.refresh(toolbar);
  21367. },
  21368. reposition: (apis, toolbar) => {
  21369. apis.reposition(toolbar);
  21370. },
  21371. toggle: (apis, toolbar) => {
  21372. apis.toggle(toolbar);
  21373. },
  21374. toggleWithoutFocusing: (apis, toolbar) => {
  21375. apis.toggle(toolbar);
  21376. },
  21377. isOpen: (apis, toolbar) => apis.isOpen(toolbar),
  21378. getOverflow: (apis, toolbar) => apis.getOverflow(toolbar)
  21379. }
  21380. });
  21381. const schema$8 = constant$1([
  21382. markers$1([
  21383. 'closedClass',
  21384. 'openClass',
  21385. 'shrinkingClass',
  21386. 'growingClass',
  21387. 'overflowToggledClass'
  21388. ]),
  21389. onHandler('onOpened'),
  21390. onHandler('onClosed')
  21391. ].concat(schema$c()));
  21392. const parts$4 = constant$1([
  21393. required({
  21394. factory: Toolbar,
  21395. schema: schema$e(),
  21396. name: 'primary'
  21397. }),
  21398. required({
  21399. factory: Toolbar,
  21400. schema: schema$e(),
  21401. name: 'overflow',
  21402. overrides: detail => {
  21403. return {
  21404. toolbarBehaviours: derive$1([
  21405. Sliding.config({
  21406. dimension: { property: 'height' },
  21407. closedClass: detail.markers.closedClass,
  21408. openClass: detail.markers.openClass,
  21409. shrinkingClass: detail.markers.shrinkingClass,
  21410. growingClass: detail.markers.growingClass,
  21411. onShrunk: comp => {
  21412. getPart(comp, detail, 'overflow-button').each(button => {
  21413. Toggling.off(button);
  21414. Focusing.focus(button);
  21415. });
  21416. detail.onClosed(comp);
  21417. },
  21418. onGrown: comp => {
  21419. Keying.focusIn(comp);
  21420. detail.onOpened(comp);
  21421. },
  21422. onStartGrow: comp => {
  21423. getPart(comp, detail, 'overflow-button').each(Toggling.on);
  21424. }
  21425. }),
  21426. Keying.config({
  21427. mode: 'acyclic',
  21428. onEscape: comp => {
  21429. getPart(comp, detail, 'overflow-button').each(Focusing.focus);
  21430. return Optional.some(true);
  21431. }
  21432. })
  21433. ])
  21434. };
  21435. }
  21436. }),
  21437. external({
  21438. name: 'overflow-button',
  21439. overrides: detail => ({
  21440. buttonBehaviours: derive$1([Toggling.config({
  21441. toggleClass: detail.markers.overflowToggledClass,
  21442. aria: { mode: 'pressed' },
  21443. toggleOnExecute: false
  21444. })])
  21445. })
  21446. }),
  21447. external({ name: 'overflow-group' })
  21448. ]);
  21449. const isOpen = (toolbar, detail) => getPart(toolbar, detail, 'overflow').map(Sliding.hasGrown).getOr(false);
  21450. const toggleToolbar = (toolbar, detail) => {
  21451. getPart(toolbar, detail, 'overflow-button').bind(() => getPart(toolbar, detail, 'overflow')).each(overf => {
  21452. refresh(toolbar, detail);
  21453. Sliding.toggleGrow(overf);
  21454. });
  21455. };
  21456. const refresh = (toolbar, detail) => {
  21457. getPart(toolbar, detail, 'overflow').each(overflow => {
  21458. refresh$2(toolbar, detail, groups => {
  21459. const builtGroups = map$2(groups, g => premade(g));
  21460. Toolbar.setGroups(overflow, builtGroups);
  21461. });
  21462. getPart(toolbar, detail, 'overflow-button').each(button => {
  21463. if (Sliding.hasGrown(overflow)) {
  21464. Toggling.on(button);
  21465. }
  21466. });
  21467. Sliding.refresh(overflow);
  21468. });
  21469. };
  21470. const factory$9 = (detail, components, spec, externals) => {
  21471. const toolbarToggleEvent = 'alloy.toolbar.toggle';
  21472. const doSetGroups = (toolbar, groups) => {
  21473. const built = map$2(groups, toolbar.getSystem().build);
  21474. detail.builtGroups.set(built);
  21475. };
  21476. return {
  21477. uid: detail.uid,
  21478. dom: detail.dom,
  21479. components,
  21480. behaviours: augment(detail.splitToolbarBehaviours, [
  21481. Coupling.config({
  21482. others: {
  21483. overflowGroup: toolbar => {
  21484. return ToolbarGroup.sketch({
  21485. ...externals['overflow-group'](),
  21486. items: [Button.sketch({
  21487. ...externals['overflow-button'](),
  21488. action: _button => {
  21489. emit(toolbar, toolbarToggleEvent);
  21490. }
  21491. })]
  21492. });
  21493. }
  21494. }
  21495. }),
  21496. config('toolbar-toggle-events', [run$1(toolbarToggleEvent, toolbar => {
  21497. toggleToolbar(toolbar, detail);
  21498. })])
  21499. ]),
  21500. apis: {
  21501. setGroups: (toolbar, groups) => {
  21502. doSetGroups(toolbar, groups);
  21503. refresh(toolbar, detail);
  21504. },
  21505. refresh: toolbar => refresh(toolbar, detail),
  21506. toggle: toolbar => toggleToolbar(toolbar, detail),
  21507. isOpen: toolbar => isOpen(toolbar, detail)
  21508. },
  21509. domModification: { attributes: { role: 'group' } }
  21510. };
  21511. };
  21512. const SplitSlidingToolbar = composite({
  21513. name: 'SplitSlidingToolbar',
  21514. configFields: schema$8(),
  21515. partFields: parts$4(),
  21516. factory: factory$9,
  21517. apis: {
  21518. setGroups: (apis, toolbar, groups) => {
  21519. apis.setGroups(toolbar, groups);
  21520. },
  21521. refresh: (apis, toolbar) => {
  21522. apis.refresh(toolbar);
  21523. },
  21524. toggle: (apis, toolbar) => {
  21525. apis.toggle(toolbar);
  21526. },
  21527. isOpen: (apis, toolbar) => apis.isOpen(toolbar)
  21528. }
  21529. });
  21530. const renderToolbarGroupCommon = toolbarGroup => {
  21531. const attributes = toolbarGroup.title.fold(() => ({}), title => ({ attributes: { title } }));
  21532. return {
  21533. dom: {
  21534. tag: 'div',
  21535. classes: ['tox-toolbar__group'],
  21536. ...attributes
  21537. },
  21538. components: [ToolbarGroup.parts.items({})],
  21539. items: toolbarGroup.items,
  21540. markers: { itemSelector: '*:not(.tox-split-button) > .tox-tbtn:not([disabled]), ' + '.tox-split-button:not([disabled]), ' + '.tox-toolbar-nav-js:not([disabled]), ' + '.tox-number-input:not([disabled])' },
  21541. tgroupBehaviours: derive$1([
  21542. Tabstopping.config({}),
  21543. Focusing.config({})
  21544. ])
  21545. };
  21546. };
  21547. const renderToolbarGroup = toolbarGroup => ToolbarGroup.sketch(renderToolbarGroupCommon(toolbarGroup));
  21548. const getToolbarBehaviours = (toolbarSpec, modeName) => {
  21549. const onAttached = runOnAttached(component => {
  21550. const groups = map$2(toolbarSpec.initGroups, renderToolbarGroup);
  21551. Toolbar.setGroups(component, groups);
  21552. });
  21553. return derive$1([
  21554. DisablingConfigs.toolbarButton(toolbarSpec.providers.isDisabled),
  21555. receivingConfig(),
  21556. Keying.config({
  21557. mode: modeName,
  21558. onEscape: toolbarSpec.onEscape,
  21559. selector: '.tox-toolbar__group'
  21560. }),
  21561. config('toolbar-events', [onAttached])
  21562. ]);
  21563. };
  21564. const renderMoreToolbarCommon = toolbarSpec => {
  21565. const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
  21566. return {
  21567. uid: toolbarSpec.uid,
  21568. dom: {
  21569. tag: 'div',
  21570. classes: ['tox-toolbar-overlord']
  21571. },
  21572. parts: {
  21573. 'overflow-group': renderToolbarGroupCommon({
  21574. title: Optional.none(),
  21575. items: []
  21576. }),
  21577. 'overflow-button': renderIconButtonSpec({
  21578. name: 'more',
  21579. icon: Optional.some('more-drawer'),
  21580. enabled: true,
  21581. tooltip: Optional.some('Reveal or hide additional toolbar items'),
  21582. primary: false,
  21583. buttonType: Optional.none(),
  21584. borderless: false
  21585. }, Optional.none(), toolbarSpec.providers)
  21586. },
  21587. splitToolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
  21588. };
  21589. };
  21590. const renderFloatingMoreToolbar = toolbarSpec => {
  21591. const baseSpec = renderMoreToolbarCommon(toolbarSpec);
  21592. const overflowXOffset = 4;
  21593. const primary = SplitFloatingToolbar.parts.primary({
  21594. dom: {
  21595. tag: 'div',
  21596. classes: ['tox-toolbar__primary']
  21597. }
  21598. });
  21599. return SplitFloatingToolbar.sketch({
  21600. ...baseSpec,
  21601. lazySink: toolbarSpec.getSink,
  21602. getOverflowBounds: () => {
  21603. const headerElem = toolbarSpec.moreDrawerData.lazyHeader().element;
  21604. const headerBounds = absolute$2(headerElem);
  21605. const docElem = documentElement(headerElem);
  21606. const docBounds = absolute$2(docElem);
  21607. const height = Math.max(docElem.dom.scrollHeight, docBounds.height);
  21608. return bounds(headerBounds.x + overflowXOffset, docBounds.y, headerBounds.width - overflowXOffset * 2, height);
  21609. },
  21610. parts: {
  21611. ...baseSpec.parts,
  21612. overflow: {
  21613. dom: {
  21614. tag: 'div',
  21615. classes: ['tox-toolbar__overflow'],
  21616. attributes: toolbarSpec.attributes
  21617. }
  21618. }
  21619. },
  21620. components: [primary],
  21621. markers: { overflowToggledClass: 'tox-tbtn--enabled' },
  21622. onOpened: comp => toolbarSpec.onToggled(comp, true),
  21623. onClosed: comp => toolbarSpec.onToggled(comp, false)
  21624. });
  21625. };
  21626. const renderSlidingMoreToolbar = toolbarSpec => {
  21627. const primary = SplitSlidingToolbar.parts.primary({
  21628. dom: {
  21629. tag: 'div',
  21630. classes: ['tox-toolbar__primary']
  21631. }
  21632. });
  21633. const overflow = SplitSlidingToolbar.parts.overflow({
  21634. dom: {
  21635. tag: 'div',
  21636. classes: ['tox-toolbar__overflow']
  21637. }
  21638. });
  21639. const baseSpec = renderMoreToolbarCommon(toolbarSpec);
  21640. return SplitSlidingToolbar.sketch({
  21641. ...baseSpec,
  21642. components: [
  21643. primary,
  21644. overflow
  21645. ],
  21646. markers: {
  21647. openClass: 'tox-toolbar__overflow--open',
  21648. closedClass: 'tox-toolbar__overflow--closed',
  21649. growingClass: 'tox-toolbar__overflow--growing',
  21650. shrinkingClass: 'tox-toolbar__overflow--shrinking',
  21651. overflowToggledClass: 'tox-tbtn--enabled'
  21652. },
  21653. onOpened: comp => {
  21654. comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'opened' });
  21655. toolbarSpec.onToggled(comp, true);
  21656. },
  21657. onClosed: comp => {
  21658. comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'closed' });
  21659. toolbarSpec.onToggled(comp, false);
  21660. }
  21661. });
  21662. };
  21663. const renderToolbar = toolbarSpec => {
  21664. const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
  21665. return Toolbar.sketch({
  21666. uid: toolbarSpec.uid,
  21667. dom: {
  21668. tag: 'div',
  21669. classes: ['tox-toolbar'].concat(toolbarSpec.type === ToolbarMode$1.scrolling ? ['tox-toolbar--scrolling'] : [])
  21670. },
  21671. components: [Toolbar.parts.groups({})],
  21672. toolbarBehaviours: getToolbarBehaviours(toolbarSpec, modeName)
  21673. });
  21674. };
  21675. const baseButtonFields = [
  21676. optionalText,
  21677. optionalIcon,
  21678. optionString('tooltip'),
  21679. defaultedStringEnum('buttonType', 'secondary', [
  21680. 'primary',
  21681. 'secondary'
  21682. ]),
  21683. defaultedBoolean('borderless', false),
  21684. requiredFunction('onAction')
  21685. ];
  21686. const normalButtonFields = [
  21687. ...baseButtonFields,
  21688. text,
  21689. requiredStringEnum('type', ['button'])
  21690. ];
  21691. const toggleButtonFields = [
  21692. ...baseButtonFields,
  21693. defaultedBoolean('active', false),
  21694. requiredStringEnum('type', ['togglebutton'])
  21695. ];
  21696. const schemaWithoutGroupButton = {
  21697. button: normalButtonFields,
  21698. togglebutton: toggleButtonFields
  21699. };
  21700. const groupFields = [
  21701. requiredStringEnum('type', ['group']),
  21702. defaultedArrayOf('buttons', [], choose$1('type', schemaWithoutGroupButton))
  21703. ];
  21704. const viewButtonSchema = choose$1('type', {
  21705. ...schemaWithoutGroupButton,
  21706. group: groupFields
  21707. });
  21708. const viewSchema = objOf([
  21709. defaultedArrayOf('buttons', [], viewButtonSchema),
  21710. requiredFunction('onShow'),
  21711. requiredFunction('onHide')
  21712. ]);
  21713. const createView = spec => asRaw('view', viewSchema, spec);
  21714. const renderButton = (spec, providers) => {
  21715. var _a, _b;
  21716. const isToggleButton = spec.type === 'togglebutton';
  21717. const optMemIcon = spec.icon.map(memIcon => renderReplaceableIconFromPack(memIcon, providers.icons)).map(record);
  21718. const getAction = () => comp => {
  21719. const setIcon = newIcon => {
  21720. optMemIcon.map(memIcon => memIcon.getOpt(comp).each(displayIcon => {
  21721. Replacing.set(displayIcon, [renderReplaceableIconFromPack(newIcon, providers.icons)]);
  21722. }));
  21723. };
  21724. const setActive = state => {
  21725. const elm = comp.element;
  21726. if (state) {
  21727. add$2(elm, 'tox-button--enabled');
  21728. set$9(elm, 'aria-pressed', true);
  21729. } else {
  21730. remove$2(elm, 'tox-button--enabled');
  21731. remove$7(elm, 'aria-pressed');
  21732. }
  21733. };
  21734. const isActive = () => has(comp.element, 'tox-button--enabled');
  21735. if (isToggleButton) {
  21736. return spec.onAction({
  21737. setIcon,
  21738. setActive,
  21739. isActive
  21740. });
  21741. }
  21742. if (spec.type === 'button') {
  21743. return spec.onAction({ setIcon });
  21744. }
  21745. };
  21746. const action = getAction();
  21747. const buttonSpec = {
  21748. ...spec,
  21749. name: isToggleButton ? spec.text.getOr(spec.icon.getOr('')) : (_a = spec.text) !== null && _a !== void 0 ? _a : spec.icon.getOr(''),
  21750. primary: spec.buttonType === 'primary',
  21751. buttonType: Optional.from(spec.buttonType),
  21752. tooltip: spec.tooltip,
  21753. icon: spec.icon,
  21754. enabled: true,
  21755. borderless: spec.borderless
  21756. };
  21757. const buttonTypeClasses = calculateClassesFromButtonType((_b = spec.buttonType) !== null && _b !== void 0 ? _b : 'secondary');
  21758. const optTranslatedText = isToggleButton ? spec.text.map(providers.translate) : Optional.some(providers.translate(spec.text));
  21759. const optTranslatedTextComponed = optTranslatedText.map(text$2);
  21760. const tooltipAttributes = buttonSpec.tooltip.or(optTranslatedText).map(tooltip => ({
  21761. 'aria-label': providers.translate(tooltip),
  21762. 'title': providers.translate(tooltip)
  21763. })).getOr({});
  21764. const optIconSpec = optMemIcon.map(memIcon => memIcon.asSpec());
  21765. const components = componentRenderPipeline([
  21766. optIconSpec,
  21767. optTranslatedTextComponed
  21768. ]);
  21769. const hasIconAndText = spec.icon.isSome() && optTranslatedTextComponed.isSome();
  21770. const dom = {
  21771. tag: 'button',
  21772. classes: buttonTypeClasses.concat(...spec.icon.isSome() && !hasIconAndText ? ['tox-button--icon'] : []).concat(...hasIconAndText ? ['tox-button--icon-and-text'] : []).concat(...spec.borderless ? ['tox-button--naked'] : []).concat(...spec.type === 'togglebutton' && spec.active ? ['tox-button--enabled'] : []),
  21773. attributes: tooltipAttributes
  21774. };
  21775. const extraBehaviours = [];
  21776. const iconButtonSpec = renderCommonSpec(buttonSpec, Optional.some(action), extraBehaviours, dom, components, providers);
  21777. return Button.sketch(iconButtonSpec);
  21778. };
  21779. const renderViewButton = (spec, providers) => renderButton(spec, providers);
  21780. const renderButtonsGroup = (spec, providers) => {
  21781. return {
  21782. dom: {
  21783. tag: 'div',
  21784. classes: ['tox-view__toolbar__group']
  21785. },
  21786. components: map$2(spec.buttons, button => renderViewButton(button, providers))
  21787. };
  21788. };
  21789. const deviceDetection = detect$2().deviceType;
  21790. const isPhone = deviceDetection.isPhone();
  21791. const isTablet = deviceDetection.isTablet();
  21792. const renderViewHeader = spec => {
  21793. let hasGroups = false;
  21794. const endButtons = map$2(spec.buttons, btnspec => {
  21795. if (btnspec.type === 'group') {
  21796. hasGroups = true;
  21797. return renderButtonsGroup(btnspec, spec.providers);
  21798. } else {
  21799. return renderViewButton(btnspec, spec.providers);
  21800. }
  21801. });
  21802. return {
  21803. uid: spec.uid,
  21804. dom: {
  21805. tag: 'div',
  21806. classes: [
  21807. !hasGroups ? 'tox-view__header' : 'tox-view__toolbar',
  21808. ...isPhone || isTablet ? [
  21809. 'tox-view--mobile',
  21810. 'tox-view--scrolling'
  21811. ] : []
  21812. ]
  21813. },
  21814. behaviours: derive$1([
  21815. Focusing.config({}),
  21816. Keying.config({
  21817. mode: 'flow',
  21818. selector: 'button, .tox-button',
  21819. focusInside: FocusInsideModes.OnEnterOrSpaceMode
  21820. })
  21821. ]),
  21822. components: hasGroups ? endButtons : [
  21823. Container.sketch({
  21824. dom: {
  21825. tag: 'div',
  21826. classes: ['tox-view__header-start']
  21827. },
  21828. components: []
  21829. }),
  21830. Container.sketch({
  21831. dom: {
  21832. tag: 'div',
  21833. classes: ['tox-view__header-end']
  21834. },
  21835. components: endButtons
  21836. })
  21837. ]
  21838. };
  21839. };
  21840. const renderViewPane = spec => {
  21841. return {
  21842. uid: spec.uid,
  21843. dom: {
  21844. tag: 'div',
  21845. classes: ['tox-view__pane']
  21846. }
  21847. };
  21848. };
  21849. const factory$8 = (detail, components, _spec, _externals) => {
  21850. const apis = {
  21851. getPane: comp => parts$a.getPart(comp, detail, 'pane'),
  21852. getOnShow: _comp => detail.viewConfig.onShow,
  21853. getOnHide: _comp => detail.viewConfig.onHide
  21854. };
  21855. return {
  21856. uid: detail.uid,
  21857. dom: detail.dom,
  21858. components,
  21859. apis
  21860. };
  21861. };
  21862. var View = composite({
  21863. name: 'silver.View',
  21864. configFields: [required$1('viewConfig')],
  21865. partFields: [
  21866. optional({
  21867. factory: { sketch: renderViewHeader },
  21868. schema: [
  21869. required$1('buttons'),
  21870. required$1('providers')
  21871. ],
  21872. name: 'header'
  21873. }),
  21874. optional({
  21875. factory: { sketch: renderViewPane },
  21876. schema: [],
  21877. name: 'pane'
  21878. })
  21879. ],
  21880. factory: factory$8,
  21881. apis: {
  21882. getPane: (apis, comp) => apis.getPane(comp),
  21883. getOnShow: (apis, comp) => apis.getOnShow(comp),
  21884. getOnHide: (apis, comp) => apis.getOnHide(comp)
  21885. }
  21886. });
  21887. const makeViews = (parts, viewConfigs, providers) => {
  21888. return mapToArray(viewConfigs, (config, name) => {
  21889. const internalViewConfig = getOrDie(createView(config));
  21890. return parts.slot(name, View.sketch({
  21891. dom: {
  21892. tag: 'div',
  21893. classes: ['tox-view']
  21894. },
  21895. viewConfig: internalViewConfig,
  21896. components: [
  21897. ...internalViewConfig.buttons.length > 0 ? [View.parts.header({
  21898. buttons: internalViewConfig.buttons,
  21899. providers
  21900. })] : [],
  21901. View.parts.pane({})
  21902. ]
  21903. }));
  21904. });
  21905. };
  21906. const makeSlotContainer = (viewConfigs, providers) => SlotContainer.sketch(parts => ({
  21907. dom: {
  21908. tag: 'div',
  21909. classes: ['tox-view-wrap__slot-container']
  21910. },
  21911. components: makeViews(parts, viewConfigs, providers),
  21912. slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
  21913. }));
  21914. const getCurrentName = slotContainer => {
  21915. return find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name));
  21916. };
  21917. const hideContainer = comp => {
  21918. const element = comp.element;
  21919. set$8(element, 'display', 'none');
  21920. set$9(element, 'aria-hidden', 'true');
  21921. };
  21922. const showContainer = comp => {
  21923. const element = comp.element;
  21924. remove$6(element, 'display');
  21925. remove$7(element, 'aria-hidden');
  21926. };
  21927. const makeViewInstanceApi = slot => ({ getContainer: constant$1(slot) });
  21928. const runOnPaneWithInstanceApi = (slotContainer, name, get) => {
  21929. SlotContainer.getSlot(slotContainer, name).each(view => {
  21930. View.getPane(view).each(pane => {
  21931. const onCallback = get(view);
  21932. onCallback(makeViewInstanceApi(pane.element.dom));
  21933. });
  21934. });
  21935. };
  21936. const runOnShow = (slotContainer, name) => runOnPaneWithInstanceApi(slotContainer, name, View.getOnShow);
  21937. const runOnHide = (slotContainer, name) => runOnPaneWithInstanceApi(slotContainer, name, View.getOnHide);
  21938. const factory$7 = (detail, spec) => {
  21939. const setViews = (comp, viewConfigs) => {
  21940. Replacing.set(comp, [makeSlotContainer(viewConfigs, spec.backstage.shared.providers)]);
  21941. };
  21942. const whichView = comp => {
  21943. return Composing.getCurrent(comp).bind(getCurrentName);
  21944. };
  21945. const toggleView = (comp, showMainView, hideMainView, name) => {
  21946. return Composing.getCurrent(comp).exists(slotContainer => {
  21947. const optCurrentSlotName = getCurrentName(slotContainer);
  21948. const isTogglingCurrentView = optCurrentSlotName.exists(current => name === current);
  21949. const exists = SlotContainer.getSlot(slotContainer, name).isSome();
  21950. if (exists) {
  21951. SlotContainer.hideAllSlots(slotContainer);
  21952. if (!isTogglingCurrentView) {
  21953. hideMainView();
  21954. showContainer(comp);
  21955. SlotContainer.showSlot(slotContainer, name);
  21956. runOnShow(slotContainer, name);
  21957. } else {
  21958. hideContainer(comp);
  21959. showMainView();
  21960. }
  21961. optCurrentSlotName.each(prevName => runOnHide(slotContainer, prevName));
  21962. }
  21963. return exists;
  21964. });
  21965. };
  21966. const apis = {
  21967. setViews,
  21968. whichView,
  21969. toggleView
  21970. };
  21971. return {
  21972. uid: detail.uid,
  21973. dom: {
  21974. tag: 'div',
  21975. classes: ['tox-view-wrap'],
  21976. attributes: { 'aria-hidden': 'true' },
  21977. styles: { display: 'none' }
  21978. },
  21979. components: [],
  21980. behaviours: derive$1([
  21981. Replacing.config({}),
  21982. Composing.config({
  21983. find: comp => {
  21984. const children = Replacing.contents(comp);
  21985. return head(children);
  21986. }
  21987. })
  21988. ]),
  21989. apis
  21990. };
  21991. };
  21992. var ViewWrapper = single({
  21993. factory: factory$7,
  21994. name: 'silver.ViewWrapper',
  21995. configFields: [required$1('backstage')],
  21996. apis: {
  21997. setViews: (apis, comp, views) => apis.setViews(comp, views),
  21998. toggleView: (apis, comp, outerContainer, editorCont, name) => apis.toggleView(comp, outerContainer, editorCont, name),
  21999. whichView: (apis, comp) => apis.whichView(comp)
  22000. }
  22001. });
  22002. const factory$6 = (detail, components, _spec) => {
  22003. let toolbarDrawerOpenState = false;
  22004. const apis = {
  22005. getSocket: comp => {
  22006. return parts$a.getPart(comp, detail, 'socket');
  22007. },
  22008. setSidebar: (comp, panelConfigs, showSidebar) => {
  22009. parts$a.getPart(comp, detail, 'sidebar').each(sidebar => setSidebar(sidebar, panelConfigs, showSidebar));
  22010. },
  22011. toggleSidebar: (comp, name) => {
  22012. parts$a.getPart(comp, detail, 'sidebar').each(sidebar => toggleSidebar(sidebar, name));
  22013. },
  22014. whichSidebar: comp => {
  22015. return parts$a.getPart(comp, detail, 'sidebar').bind(whichSidebar).getOrNull();
  22016. },
  22017. getHeader: comp => {
  22018. return parts$a.getPart(comp, detail, 'header');
  22019. },
  22020. getToolbar: comp => {
  22021. return parts$a.getPart(comp, detail, 'toolbar');
  22022. },
  22023. setToolbar: (comp, groups) => {
  22024. parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
  22025. const renderedGroups = map$2(groups, renderToolbarGroup);
  22026. toolbar.getApis().setGroups(toolbar, renderedGroups);
  22027. });
  22028. },
  22029. setToolbars: (comp, toolbars) => {
  22030. parts$a.getPart(comp, detail, 'multiple-toolbar').each(mToolbar => {
  22031. const renderedToolbars = map$2(toolbars, g => map$2(g, renderToolbarGroup));
  22032. CustomList.setItems(mToolbar, renderedToolbars);
  22033. });
  22034. },
  22035. refreshToolbar: comp => {
  22036. const toolbar = parts$a.getPart(comp, detail, 'toolbar');
  22037. toolbar.each(toolbar => toolbar.getApis().refresh(toolbar));
  22038. },
  22039. toggleToolbarDrawer: comp => {
  22040. parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
  22041. mapFrom(toolbar.getApis().toggle, toggle => toggle(toolbar));
  22042. });
  22043. },
  22044. toggleToolbarDrawerWithoutFocusing: comp => {
  22045. parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
  22046. mapFrom(toolbar.getApis().toggleWithoutFocusing, toggleWithoutFocusing => toggleWithoutFocusing(toolbar));
  22047. });
  22048. },
  22049. isToolbarDrawerToggled: comp => {
  22050. return parts$a.getPart(comp, detail, 'toolbar').bind(toolbar => Optional.from(toolbar.getApis().isOpen).map(isOpen => isOpen(toolbar))).getOr(false);
  22051. },
  22052. getThrobber: comp => {
  22053. return parts$a.getPart(comp, detail, 'throbber');
  22054. },
  22055. focusToolbar: comp => {
  22056. const optToolbar = parts$a.getPart(comp, detail, 'toolbar').orThunk(() => parts$a.getPart(comp, detail, 'multiple-toolbar'));
  22057. optToolbar.each(toolbar => {
  22058. Keying.focusIn(toolbar);
  22059. });
  22060. },
  22061. setMenubar: (comp, menus) => {
  22062. parts$a.getPart(comp, detail, 'menubar').each(menubar => {
  22063. SilverMenubar.setMenus(menubar, menus);
  22064. });
  22065. },
  22066. focusMenubar: comp => {
  22067. parts$a.getPart(comp, detail, 'menubar').each(menubar => {
  22068. SilverMenubar.focus(menubar);
  22069. });
  22070. },
  22071. setViews: (comp, viewConfigs) => {
  22072. parts$a.getPart(comp, detail, 'viewWrapper').each(wrapper => {
  22073. ViewWrapper.setViews(wrapper, viewConfigs);
  22074. });
  22075. },
  22076. toggleView: (comp, name) => {
  22077. return parts$a.getPart(comp, detail, 'viewWrapper').exists(wrapper => ViewWrapper.toggleView(wrapper, () => apis.showMainView(comp), () => apis.hideMainView(comp), name));
  22078. },
  22079. whichView: comp => {
  22080. return parts$a.getPart(comp, detail, 'viewWrapper').bind(ViewWrapper.whichView).getOrNull();
  22081. },
  22082. hideMainView: comp => {
  22083. toolbarDrawerOpenState = apis.isToolbarDrawerToggled(comp);
  22084. if (toolbarDrawerOpenState) {
  22085. apis.toggleToolbarDrawer(comp);
  22086. }
  22087. parts$a.getPart(comp, detail, 'editorContainer').each(editorContainer => {
  22088. const element = editorContainer.element;
  22089. set$8(element, 'display', 'none');
  22090. set$9(element, 'aria-hidden', 'true');
  22091. });
  22092. },
  22093. showMainView: comp => {
  22094. if (toolbarDrawerOpenState) {
  22095. apis.toggleToolbarDrawer(comp);
  22096. }
  22097. parts$a.getPart(comp, detail, 'editorContainer').each(editorContainer => {
  22098. const element = editorContainer.element;
  22099. remove$6(element, 'display');
  22100. remove$7(element, 'aria-hidden');
  22101. });
  22102. }
  22103. };
  22104. return {
  22105. uid: detail.uid,
  22106. dom: detail.dom,
  22107. components,
  22108. apis,
  22109. behaviours: detail.behaviours
  22110. };
  22111. };
  22112. const partMenubar = partType.optional({
  22113. factory: SilverMenubar,
  22114. name: 'menubar',
  22115. schema: [required$1('backstage')]
  22116. });
  22117. const toolbarFactory = spec => {
  22118. if (spec.type === ToolbarMode$1.sliding) {
  22119. return renderSlidingMoreToolbar;
  22120. } else if (spec.type === ToolbarMode$1.floating) {
  22121. return renderFloatingMoreToolbar;
  22122. } else {
  22123. return renderToolbar;
  22124. }
  22125. };
  22126. const partMultipleToolbar = partType.optional({
  22127. factory: {
  22128. sketch: spec => CustomList.sketch({
  22129. uid: spec.uid,
  22130. dom: spec.dom,
  22131. listBehaviours: derive$1([Keying.config({
  22132. mode: 'acyclic',
  22133. selector: '.tox-toolbar'
  22134. })]),
  22135. makeItem: () => renderToolbar({
  22136. type: spec.type,
  22137. uid: generate$6('multiple-toolbar-item'),
  22138. cyclicKeying: false,
  22139. initGroups: [],
  22140. providers: spec.providers,
  22141. onEscape: () => {
  22142. spec.onEscape();
  22143. return Optional.some(true);
  22144. }
  22145. }),
  22146. setupItem: (_mToolbar, tc, data, _index) => {
  22147. Toolbar.setGroups(tc, data);
  22148. },
  22149. shell: true
  22150. })
  22151. },
  22152. name: 'multiple-toolbar',
  22153. schema: [
  22154. required$1('dom'),
  22155. required$1('onEscape')
  22156. ]
  22157. });
  22158. const partToolbar = partType.optional({
  22159. factory: {
  22160. sketch: spec => {
  22161. const renderer = toolbarFactory(spec);
  22162. const toolbarSpec = {
  22163. type: spec.type,
  22164. uid: spec.uid,
  22165. onEscape: () => {
  22166. spec.onEscape();
  22167. return Optional.some(true);
  22168. },
  22169. onToggled: (_comp, state) => spec.onToolbarToggled(state),
  22170. cyclicKeying: false,
  22171. initGroups: [],
  22172. getSink: spec.getSink,
  22173. providers: spec.providers,
  22174. moreDrawerData: {
  22175. lazyToolbar: spec.lazyToolbar,
  22176. lazyMoreButton: spec.lazyMoreButton,
  22177. lazyHeader: spec.lazyHeader
  22178. },
  22179. attributes: spec.attributes
  22180. };
  22181. return renderer(toolbarSpec);
  22182. }
  22183. },
  22184. name: 'toolbar',
  22185. schema: [
  22186. required$1('dom'),
  22187. required$1('onEscape'),
  22188. required$1('getSink')
  22189. ]
  22190. });
  22191. const partHeader = partType.optional({
  22192. factory: { sketch: renderHeader },
  22193. name: 'header',
  22194. schema: [required$1('dom')]
  22195. });
  22196. const partPromotion = partType.optional({
  22197. factory: { sketch: renderPromotion },
  22198. name: 'promotion',
  22199. schema: [required$1('dom')]
  22200. });
  22201. const partSocket = partType.optional({
  22202. name: 'socket',
  22203. schema: [required$1('dom')]
  22204. });
  22205. const partSidebar = partType.optional({
  22206. factory: { sketch: renderSidebar },
  22207. name: 'sidebar',
  22208. schema: [required$1('dom')]
  22209. });
  22210. const partThrobber = partType.optional({
  22211. factory: { sketch: renderThrobber },
  22212. name: 'throbber',
  22213. schema: [required$1('dom')]
  22214. });
  22215. const partViewWrapper = partType.optional({
  22216. factory: ViewWrapper,
  22217. name: 'viewWrapper',
  22218. schema: [required$1('backstage')]
  22219. });
  22220. const renderEditorContainer = spec => ({
  22221. uid: spec.uid,
  22222. dom: {
  22223. tag: 'div',
  22224. classes: ['tox-editor-container']
  22225. },
  22226. components: spec.components
  22227. });
  22228. const partEditorContainer = partType.optional({
  22229. factory: { sketch: renderEditorContainer },
  22230. name: 'editorContainer',
  22231. schema: []
  22232. });
  22233. var OuterContainer = composite({
  22234. name: 'OuterContainer',
  22235. factory: factory$6,
  22236. configFields: [
  22237. required$1('dom'),
  22238. required$1('behaviours')
  22239. ],
  22240. partFields: [
  22241. partHeader,
  22242. partMenubar,
  22243. partToolbar,
  22244. partMultipleToolbar,
  22245. partSocket,
  22246. partSidebar,
  22247. partPromotion,
  22248. partThrobber,
  22249. partViewWrapper,
  22250. partEditorContainer
  22251. ],
  22252. apis: {
  22253. getSocket: (apis, comp) => {
  22254. return apis.getSocket(comp);
  22255. },
  22256. setSidebar: (apis, comp, panelConfigs, showSidebar) => {
  22257. apis.setSidebar(comp, panelConfigs, showSidebar);
  22258. },
  22259. toggleSidebar: (apis, comp, name) => {
  22260. apis.toggleSidebar(comp, name);
  22261. },
  22262. whichSidebar: (apis, comp) => {
  22263. return apis.whichSidebar(comp);
  22264. },
  22265. getHeader: (apis, comp) => {
  22266. return apis.getHeader(comp);
  22267. },
  22268. getToolbar: (apis, comp) => {
  22269. return apis.getToolbar(comp);
  22270. },
  22271. setToolbar: (apis, comp, groups) => {
  22272. apis.setToolbar(comp, groups);
  22273. },
  22274. setToolbars: (apis, comp, toolbars) => {
  22275. apis.setToolbars(comp, toolbars);
  22276. },
  22277. refreshToolbar: (apis, comp) => {
  22278. return apis.refreshToolbar(comp);
  22279. },
  22280. toggleToolbarDrawer: (apis, comp) => {
  22281. apis.toggleToolbarDrawer(comp);
  22282. },
  22283. toggleToolbarDrawerWithoutFocusing: (apis, comp) => {
  22284. apis.toggleToolbarDrawerWithoutFocusing(comp);
  22285. },
  22286. isToolbarDrawerToggled: (apis, comp) => {
  22287. return apis.isToolbarDrawerToggled(comp);
  22288. },
  22289. getThrobber: (apis, comp) => {
  22290. return apis.getThrobber(comp);
  22291. },
  22292. setMenubar: (apis, comp, menus) => {
  22293. apis.setMenubar(comp, menus);
  22294. },
  22295. focusMenubar: (apis, comp) => {
  22296. apis.focusMenubar(comp);
  22297. },
  22298. focusToolbar: (apis, comp) => {
  22299. apis.focusToolbar(comp);
  22300. },
  22301. setViews: (apis, comp, views) => {
  22302. apis.setViews(comp, views);
  22303. },
  22304. toggleView: (apis, comp, name) => {
  22305. return apis.toggleView(comp, name);
  22306. },
  22307. whichView: (apis, comp) => {
  22308. return apis.whichView(comp);
  22309. }
  22310. }
  22311. });
  22312. const defaultMenubar = 'file edit view insert format tools table help';
  22313. const defaultMenus = {
  22314. file: {
  22315. title: 'File',
  22316. items: 'newdocument restoredraft | preview | export print | deleteallconversations'
  22317. },
  22318. edit: {
  22319. title: 'Edit',
  22320. items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
  22321. },
  22322. view: {
  22323. title: 'View',
  22324. items: 'code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments'
  22325. },
  22326. insert: {
  22327. title: 'Insert',
  22328. items: 'image link media addcomment pageembed template inserttemplate codesample inserttable accordion | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents footnotes | mergetags | insertdatetime'
  22329. },
  22330. format: {
  22331. title: 'Format',
  22332. items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat'
  22333. },
  22334. tools: {
  22335. title: 'Tools',
  22336. items: 'aidialog aishortcuts | spellchecker spellcheckerlanguage | autocorrect capitalization | a11ycheck code typography wordcount addtemplate'
  22337. },
  22338. table: {
  22339. title: 'Table',
  22340. items: 'inserttable | cell row column | advtablesort | tableprops deletetable'
  22341. },
  22342. help: {
  22343. title: 'Help',
  22344. items: 'help'
  22345. }
  22346. };
  22347. const make = (menu, registry, editor) => {
  22348. const removedMenuItems = getRemovedMenuItems(editor).split(/[ ,]/);
  22349. return {
  22350. text: menu.title,
  22351. getItems: () => bind$3(menu.items, i => {
  22352. const itemName = i.toLowerCase();
  22353. if (itemName.trim().length === 0) {
  22354. return [];
  22355. } else if (exists(removedMenuItems, removedMenuItem => removedMenuItem === itemName)) {
  22356. return [];
  22357. } else if (itemName === 'separator' || itemName === '|') {
  22358. return [{ type: 'separator' }];
  22359. } else if (registry.menuItems[itemName]) {
  22360. return [registry.menuItems[itemName]];
  22361. } else {
  22362. return [];
  22363. }
  22364. })
  22365. };
  22366. };
  22367. const parseItemsString = items => {
  22368. return items.split(' ');
  22369. };
  22370. const identifyMenus = (editor, registry) => {
  22371. const rawMenuData = {
  22372. ...defaultMenus,
  22373. ...registry.menus
  22374. };
  22375. const userDefinedMenus = keys(registry.menus).length > 0;
  22376. const menubar = registry.menubar === undefined || registry.menubar === true ? parseItemsString(defaultMenubar) : parseItemsString(registry.menubar === false ? '' : registry.menubar);
  22377. const validMenus = filter$2(menubar, menuName => {
  22378. const isDefaultMenu = has$2(defaultMenus, menuName);
  22379. if (userDefinedMenus) {
  22380. return isDefaultMenu || get$g(registry.menus, menuName).exists(menu => has$2(menu, 'items'));
  22381. } else {
  22382. return isDefaultMenu;
  22383. }
  22384. });
  22385. const menus = map$2(validMenus, menuName => {
  22386. const menuData = rawMenuData[menuName];
  22387. return make({
  22388. title: menuData.title,
  22389. items: parseItemsString(menuData.items)
  22390. }, registry, editor);
  22391. });
  22392. return filter$2(menus, menu => {
  22393. const isNotSeparator = item => isString(item) || item.type !== 'separator';
  22394. return menu.getItems().length > 0 && exists(menu.getItems(), isNotSeparator);
  22395. });
  22396. };
  22397. const fireSkinLoaded = editor => {
  22398. const done = () => {
  22399. editor._skinLoaded = true;
  22400. fireSkinLoaded$1(editor);
  22401. };
  22402. return () => {
  22403. if (editor.initialized) {
  22404. done();
  22405. } else {
  22406. editor.on('init', done);
  22407. }
  22408. };
  22409. };
  22410. const fireSkinLoadError = (editor, err) => () => fireSkinLoadError$1(editor, { message: err });
  22411. const loadStylesheet = (editor, stylesheetUrl, styleSheetLoader) => {
  22412. editor.on('remove', () => styleSheetLoader.unload(stylesheetUrl));
  22413. return styleSheetLoader.load(stylesheetUrl);
  22414. };
  22415. const loadRawCss = (editor, key, css, styleSheetLoader) => {
  22416. editor.on('remove', () => styleSheetLoader.unloadRawCss(key));
  22417. return styleSheetLoader.loadRawCss(key, css);
  22418. };
  22419. const loadUiSkins = async (editor, skinUrl) => {
  22420. const skinResourceIdentifier = getSkinUrlOption(editor).getOr('default');
  22421. const skinUiCss = 'ui/' + skinResourceIdentifier + '/skin.css';
  22422. const css = tinymce.Resource.get(skinUiCss);
  22423. if (isString(css)) {
  22424. return Promise.resolve(loadRawCss(editor, skinUiCss, css, editor.ui.styleSheetLoader));
  22425. } else {
  22426. const skinUiCss = skinUrl + '/skin.min.css';
  22427. return loadStylesheet(editor, skinUiCss, editor.ui.styleSheetLoader);
  22428. }
  22429. };
  22430. const loadShadowDomUiSkins = async (editor, skinUrl) => {
  22431. const isInShadowRoot$1 = isInShadowRoot(SugarElement.fromDom(editor.getElement()));
  22432. if (isInShadowRoot$1) {
  22433. const skinResourceIdentifier = getSkinUrlOption(editor).getOr('default');
  22434. const shadowDomSkinCss = 'ui/' + skinResourceIdentifier + '/skin.shadowdom.css';
  22435. const css = tinymce.Resource.get(shadowDomSkinCss);
  22436. if (isString(css)) {
  22437. loadRawCss(editor, shadowDomSkinCss, css, global$7.DOM.styleSheetLoader);
  22438. return Promise.resolve();
  22439. } else {
  22440. const shadowDomSkinCss = skinUrl + '/skin.shadowdom.min.css';
  22441. return loadStylesheet(editor, shadowDomSkinCss, global$7.DOM.styleSheetLoader);
  22442. }
  22443. }
  22444. };
  22445. const loadUrlSkin = async (isInline, editor) => {
  22446. getSkinUrlOption(editor).fold(() => {
  22447. const skinResourceIdentifier = getSkinUrl(editor);
  22448. if (skinResourceIdentifier) {
  22449. editor.contentCSS.push(skinResourceIdentifier + (isInline ? '/content.inline' : '/content') + '.min.css');
  22450. }
  22451. }, skinUrl => {
  22452. const skinContentCss = 'ui/' + skinUrl + (isInline ? '/content.inline' : '/content') + '.css';
  22453. const css = tinymce.Resource.get(skinContentCss);
  22454. if (isString(css)) {
  22455. loadRawCss(editor, skinContentCss, css, editor.ui.styleSheetLoader);
  22456. } else {
  22457. const skinResourceIdentifier = getSkinUrl(editor);
  22458. if (skinResourceIdentifier) {
  22459. editor.contentCSS.push(skinResourceIdentifier + (isInline ? '/content.inline' : '/content') + '.min.css');
  22460. }
  22461. }
  22462. });
  22463. const skinUrl = getSkinUrl(editor);
  22464. if (!isSkinDisabled(editor) && isString(skinUrl)) {
  22465. return Promise.all([
  22466. loadUiSkins(editor, skinUrl),
  22467. loadShadowDomUiSkins(editor, skinUrl)
  22468. ]).then();
  22469. }
  22470. };
  22471. const loadSkin = (isInline, editor) => {
  22472. return loadUrlSkin(isInline, editor).then(fireSkinLoaded(editor), fireSkinLoadError(editor, 'Skin could not be loaded'));
  22473. };
  22474. const iframe = curry(loadSkin, false);
  22475. const inline = curry(loadSkin, true);
  22476. const makeTooltipText = (editor, labelWithPlaceholder, value) => editor.translate([
  22477. labelWithPlaceholder,
  22478. editor.translate(value)
  22479. ]);
  22480. const generateSelectItems = (backstage, spec) => {
  22481. const generateItem = (rawItem, response, invalid, value) => {
  22482. const translatedText = backstage.shared.providers.translate(rawItem.title);
  22483. if (rawItem.type === 'separator') {
  22484. return Optional.some({
  22485. type: 'separator',
  22486. text: translatedText
  22487. });
  22488. } else if (rawItem.type === 'submenu') {
  22489. const items = bind$3(rawItem.getStyleItems(), si => validate(si, response, value));
  22490. if (response === 0 && items.length <= 0) {
  22491. return Optional.none();
  22492. } else {
  22493. return Optional.some({
  22494. type: 'nestedmenuitem',
  22495. text: translatedText,
  22496. enabled: items.length > 0,
  22497. getSubmenuItems: () => bind$3(rawItem.getStyleItems(), si => validate(si, response, value))
  22498. });
  22499. }
  22500. } else {
  22501. return Optional.some({
  22502. type: 'togglemenuitem',
  22503. text: translatedText,
  22504. icon: rawItem.icon,
  22505. active: rawItem.isSelected(value),
  22506. enabled: !invalid,
  22507. onAction: spec.onAction(rawItem),
  22508. ...rawItem.getStylePreview().fold(() => ({}), preview => ({ meta: { style: preview } }))
  22509. });
  22510. }
  22511. };
  22512. const validate = (item, response, value) => {
  22513. const invalid = item.type === 'formatter' && spec.isInvalid(item);
  22514. if (response === 0) {
  22515. return invalid ? [] : generateItem(item, response, false, value).toArray();
  22516. } else {
  22517. return generateItem(item, response, invalid, value).toArray();
  22518. }
  22519. };
  22520. const validateItems = preItems => {
  22521. const value = spec.getCurrentValue();
  22522. const response = spec.shouldHide ? 0 : 1;
  22523. return bind$3(preItems, item => validate(item, response, value));
  22524. };
  22525. const getFetch = (backstage, getStyleItems) => (comp, callback) => {
  22526. const preItems = getStyleItems();
  22527. const items = validateItems(preItems);
  22528. const menu = build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
  22529. isHorizontalMenu: false,
  22530. search: Optional.none()
  22531. });
  22532. callback(menu);
  22533. };
  22534. return {
  22535. validateItems,
  22536. getFetch
  22537. };
  22538. };
  22539. const createMenuItems = (editor, backstage, spec) => {
  22540. const dataset = spec.dataset;
  22541. const getStyleItems = dataset.type === 'basic' ? () => map$2(dataset.data, d => processBasic(d, spec.isSelectedFor, spec.getPreviewFor)) : dataset.getData;
  22542. return {
  22543. items: generateSelectItems(backstage, spec),
  22544. getStyleItems
  22545. };
  22546. };
  22547. const createSelectButton = (editor, backstage, spec, tooltipWithPlaceholder, textUpdateEventName) => {
  22548. const {items, getStyleItems} = createMenuItems(editor, backstage, spec);
  22549. const getApi = comp => ({
  22550. getComponent: constant$1(comp),
  22551. setTooltip: tooltip => {
  22552. const translatedTooltip = backstage.shared.providers.translate(tooltip);
  22553. setAll$1(comp.element, {
  22554. 'aria-label': translatedTooltip,
  22555. 'title': translatedTooltip
  22556. });
  22557. }
  22558. });
  22559. const onSetup = api => {
  22560. const handler = e => api.setTooltip(makeTooltipText(editor, tooltipWithPlaceholder, e.value));
  22561. editor.on(textUpdateEventName, handler);
  22562. return composeUnbinders(onSetupEvent(editor, 'NodeChange', api => {
  22563. const comp = api.getComponent();
  22564. spec.updateText(comp);
  22565. Disabling.set(api.getComponent(), !editor.selection.isEditable());
  22566. })(api), () => editor.off(textUpdateEventName, handler));
  22567. };
  22568. return renderCommonDropdown({
  22569. text: spec.icon.isSome() ? Optional.none() : spec.text,
  22570. icon: spec.icon,
  22571. tooltip: Optional.from(spec.tooltip),
  22572. role: Optional.none(),
  22573. fetch: items.getFetch(backstage, getStyleItems),
  22574. onSetup,
  22575. getApi,
  22576. columns: 1,
  22577. presets: 'normal',
  22578. classes: spec.icon.isSome() ? [] : ['bespoke'],
  22579. dropdownBehaviours: []
  22580. }, 'tox-tbtn', backstage.shared);
  22581. };
  22582. const process = rawFormats => map$2(rawFormats, item => {
  22583. let title = item, format = item;
  22584. const values = item.split('=');
  22585. if (values.length > 1) {
  22586. title = values[0];
  22587. format = values[1];
  22588. }
  22589. return {
  22590. title,
  22591. format
  22592. };
  22593. });
  22594. const buildBasicStaticDataset = data => ({
  22595. type: 'basic',
  22596. data
  22597. });
  22598. var Delimiter;
  22599. (function (Delimiter) {
  22600. Delimiter[Delimiter['SemiColon'] = 0] = 'SemiColon';
  22601. Delimiter[Delimiter['Space'] = 1] = 'Space';
  22602. }(Delimiter || (Delimiter = {})));
  22603. const split = (rawFormats, delimiter) => {
  22604. if (delimiter === Delimiter.SemiColon) {
  22605. return rawFormats.replace(/;$/, '').split(';');
  22606. } else {
  22607. return rawFormats.split(' ');
  22608. }
  22609. };
  22610. const buildBasicSettingsDataset = (editor, settingName, delimiter) => {
  22611. const rawFormats = editor.options.get(settingName);
  22612. const data = process(split(rawFormats, delimiter));
  22613. return {
  22614. type: 'basic',
  22615. data
  22616. };
  22617. };
  22618. const menuTitle$4 = 'Align';
  22619. const btnTooltip$4 = 'Alignment {0}';
  22620. const fallbackAlignment = 'left';
  22621. const alignMenuItems = [
  22622. {
  22623. title: 'Left',
  22624. icon: 'align-left',
  22625. format: 'alignleft',
  22626. command: 'JustifyLeft'
  22627. },
  22628. {
  22629. title: 'Center',
  22630. icon: 'align-center',
  22631. format: 'aligncenter',
  22632. command: 'JustifyCenter'
  22633. },
  22634. {
  22635. title: 'Right',
  22636. icon: 'align-right',
  22637. format: 'alignright',
  22638. command: 'JustifyRight'
  22639. },
  22640. {
  22641. title: 'Justify',
  22642. icon: 'align-justify',
  22643. format: 'alignjustify',
  22644. command: 'JustifyFull'
  22645. }
  22646. ];
  22647. const getSpec$4 = editor => {
  22648. const getMatchingValue = () => find$5(alignMenuItems, item => editor.formatter.match(item.format));
  22649. const isSelectedFor = format => () => editor.formatter.match(format);
  22650. const getPreviewFor = _format => Optional.none;
  22651. const updateSelectMenuIcon = comp => {
  22652. const match = getMatchingValue();
  22653. const alignment = match.fold(constant$1(fallbackAlignment), item => item.title.toLowerCase());
  22654. emitWith(comp, updateMenuIcon, { icon: `align-${ alignment }` });
  22655. fireAlignTextUpdate(editor, { value: alignment });
  22656. };
  22657. const dataset = buildBasicStaticDataset(alignMenuItems);
  22658. const onAction = rawItem => () => find$5(alignMenuItems, item => item.format === rawItem.format).each(item => editor.execCommand(item.command));
  22659. return {
  22660. tooltip: makeTooltipText(editor, btnTooltip$4, fallbackAlignment),
  22661. text: Optional.none(),
  22662. icon: Optional.some('align-left'),
  22663. isSelectedFor,
  22664. getCurrentValue: Optional.none,
  22665. getPreviewFor,
  22666. onAction,
  22667. updateText: updateSelectMenuIcon,
  22668. dataset,
  22669. shouldHide: false,
  22670. isInvalid: item => !editor.formatter.canApply(item.format)
  22671. };
  22672. };
  22673. const createAlignButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$4(editor), btnTooltip$4, 'AlignTextUpdate');
  22674. const createAlignMenu = (editor, backstage) => {
  22675. const menuItems = createMenuItems(editor, backstage, getSpec$4(editor));
  22676. editor.ui.registry.addNestedMenuItem('align', {
  22677. text: backstage.shared.providers.translate(menuTitle$4),
  22678. onSetup: onSetupEditableToggle(editor),
  22679. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  22680. });
  22681. };
  22682. const findNearest = (editor, getStyles) => {
  22683. const styles = getStyles();
  22684. const formats = map$2(styles, style => style.format);
  22685. return Optional.from(editor.formatter.closest(formats)).bind(fmt => find$5(styles, data => data.format === fmt)).orThunk(() => someIf(editor.formatter.match('p'), {
  22686. title: 'Paragraph',
  22687. format: 'p'
  22688. }));
  22689. };
  22690. const menuTitle$3 = 'Blocks';
  22691. const btnTooltip$3 = 'Block {0}';
  22692. const fallbackFormat = 'Paragraph';
  22693. const getSpec$3 = editor => {
  22694. const isSelectedFor = format => () => editor.formatter.match(format);
  22695. const getPreviewFor = format => () => {
  22696. const fmt = editor.formatter.get(format);
  22697. if (fmt) {
  22698. return Optional.some({
  22699. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  22700. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  22701. });
  22702. } else {
  22703. return Optional.none();
  22704. }
  22705. };
  22706. const updateSelectMenuText = comp => {
  22707. const detectedFormat = findNearest(editor, () => dataset.data);
  22708. const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
  22709. emitWith(comp, updateMenuText, { text });
  22710. fireBlocksTextUpdate(editor, { value: text });
  22711. };
  22712. const dataset = buildBasicSettingsDataset(editor, 'block_formats', Delimiter.SemiColon);
  22713. return {
  22714. tooltip: makeTooltipText(editor, btnTooltip$3, fallbackFormat),
  22715. text: Optional.some(fallbackFormat),
  22716. icon: Optional.none(),
  22717. isSelectedFor,
  22718. getCurrentValue: Optional.none,
  22719. getPreviewFor,
  22720. onAction: onActionToggleFormat$1(editor),
  22721. updateText: updateSelectMenuText,
  22722. dataset,
  22723. shouldHide: false,
  22724. isInvalid: item => !editor.formatter.canApply(item.format)
  22725. };
  22726. };
  22727. const createBlocksButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$3(editor), btnTooltip$3, 'BlocksTextUpdate');
  22728. const createBlocksMenu = (editor, backstage) => {
  22729. const menuItems = createMenuItems(editor, backstage, getSpec$3(editor));
  22730. editor.ui.registry.addNestedMenuItem('blocks', {
  22731. text: menuTitle$3,
  22732. onSetup: onSetupEditableToggle(editor),
  22733. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  22734. });
  22735. };
  22736. const menuTitle$2 = 'Fonts';
  22737. const btnTooltip$2 = 'Font {0}';
  22738. const systemFont = 'System Font';
  22739. const systemStackFonts = [
  22740. '-apple-system',
  22741. 'Segoe UI',
  22742. 'Roboto',
  22743. 'Helvetica Neue',
  22744. 'sans-serif'
  22745. ];
  22746. const splitFonts = fontFamily => {
  22747. const fonts = fontFamily.split(/\s*,\s*/);
  22748. return map$2(fonts, font => font.replace(/^['"]+|['"]+$/g, ''));
  22749. };
  22750. const matchesStack = (fonts, stack) => stack.length > 0 && forall(stack, font => fonts.indexOf(font.toLowerCase()) > -1);
  22751. const isSystemFontStack = (fontFamily, userStack) => {
  22752. if (fontFamily.indexOf('-apple-system') === 0 || userStack.length > 0) {
  22753. const fonts = splitFonts(fontFamily.toLowerCase());
  22754. return matchesStack(fonts, systemStackFonts) || matchesStack(fonts, userStack);
  22755. } else {
  22756. return false;
  22757. }
  22758. };
  22759. const getSpec$2 = editor => {
  22760. const getMatchingValue = () => {
  22761. const getFirstFont = fontFamily => fontFamily ? splitFonts(fontFamily)[0] : '';
  22762. const fontFamily = editor.queryCommandValue('FontName');
  22763. const items = dataset.data;
  22764. const font = fontFamily ? fontFamily.toLowerCase() : '';
  22765. const userStack = getDefaultFontStack(editor);
  22766. const matchOpt = find$5(items, item => {
  22767. const format = item.format;
  22768. return format.toLowerCase() === font || getFirstFont(format).toLowerCase() === getFirstFont(font).toLowerCase();
  22769. }).orThunk(() => {
  22770. return someIf(isSystemFontStack(font, userStack), {
  22771. title: systemFont,
  22772. format: font
  22773. });
  22774. });
  22775. return {
  22776. matchOpt,
  22777. font: fontFamily
  22778. };
  22779. };
  22780. const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
  22781. const getCurrentValue = () => {
  22782. const {matchOpt} = getMatchingValue();
  22783. return matchOpt;
  22784. };
  22785. const getPreviewFor = item => () => Optional.some({
  22786. tag: 'div',
  22787. styles: item.indexOf('dings') === -1 ? { 'font-family': item } : {}
  22788. });
  22789. const onAction = rawItem => () => {
  22790. editor.undoManager.transact(() => {
  22791. editor.focus();
  22792. editor.execCommand('FontName', false, rawItem.format);
  22793. });
  22794. };
  22795. const updateSelectMenuText = comp => {
  22796. const {matchOpt, font} = getMatchingValue();
  22797. const text = matchOpt.fold(constant$1(font), item => item.title);
  22798. emitWith(comp, updateMenuText, { text });
  22799. fireFontFamilyTextUpdate(editor, { value: text });
  22800. };
  22801. const dataset = buildBasicSettingsDataset(editor, 'font_family_formats', Delimiter.SemiColon);
  22802. return {
  22803. tooltip: makeTooltipText(editor, btnTooltip$2, systemFont),
  22804. text: Optional.some(systemFont),
  22805. icon: Optional.none(),
  22806. isSelectedFor,
  22807. getCurrentValue,
  22808. getPreviewFor,
  22809. onAction,
  22810. updateText: updateSelectMenuText,
  22811. dataset,
  22812. shouldHide: false,
  22813. isInvalid: never
  22814. };
  22815. };
  22816. const createFontFamilyButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$2(editor), btnTooltip$2, 'FontFamilyTextUpdate');
  22817. const createFontFamilyMenu = (editor, backstage) => {
  22818. const menuItems = createMenuItems(editor, backstage, getSpec$2(editor));
  22819. editor.ui.registry.addNestedMenuItem('fontfamily', {
  22820. text: backstage.shared.providers.translate(menuTitle$2),
  22821. onSetup: onSetupEditableToggle(editor),
  22822. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  22823. });
  22824. };
  22825. const units = {
  22826. unsupportedLength: [
  22827. 'em',
  22828. 'ex',
  22829. 'cap',
  22830. 'ch',
  22831. 'ic',
  22832. 'rem',
  22833. 'lh',
  22834. 'rlh',
  22835. 'vw',
  22836. 'vh',
  22837. 'vi',
  22838. 'vb',
  22839. 'vmin',
  22840. 'vmax',
  22841. 'cm',
  22842. 'mm',
  22843. 'Q',
  22844. 'in',
  22845. 'pc',
  22846. 'pt',
  22847. 'px'
  22848. ],
  22849. fixed: [
  22850. 'px',
  22851. 'pt'
  22852. ],
  22853. relative: ['%'],
  22854. empty: ['']
  22855. };
  22856. const pattern = (() => {
  22857. const decimalDigits = '[0-9]+';
  22858. const signedInteger = '[+-]?' + decimalDigits;
  22859. const exponentPart = '[eE]' + signedInteger;
  22860. const dot = '\\.';
  22861. const opt = input => `(?:${ input })?`;
  22862. const unsignedDecimalLiteral = [
  22863. 'Infinity',
  22864. decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
  22865. dot + decimalDigits + opt(exponentPart),
  22866. decimalDigits + opt(exponentPart)
  22867. ].join('|');
  22868. const float = `[+-]?(?:${ unsignedDecimalLiteral })`;
  22869. return new RegExp(`^(${ float })(.*)$`);
  22870. })();
  22871. const isUnit = (unit, accepted) => exists(accepted, acc => exists(units[acc], check => unit === check));
  22872. const parse = (input, accepted) => {
  22873. const match = Optional.from(pattern.exec(input));
  22874. return match.bind(array => {
  22875. const value = Number(array[1]);
  22876. const unitRaw = array[2];
  22877. if (isUnit(unitRaw, accepted)) {
  22878. return Optional.some({
  22879. value,
  22880. unit: unitRaw
  22881. });
  22882. } else {
  22883. return Optional.none();
  22884. }
  22885. });
  22886. };
  22887. const normalise = (input, accepted) => parse(input, accepted).map(({value, unit}) => value + unit);
  22888. const Keys = {
  22889. tab: constant$1(9),
  22890. escape: constant$1(27),
  22891. enter: constant$1(13),
  22892. backspace: constant$1(8),
  22893. delete: constant$1(46),
  22894. left: constant$1(37),
  22895. up: constant$1(38),
  22896. right: constant$1(39),
  22897. down: constant$1(40),
  22898. space: constant$1(32),
  22899. home: constant$1(36),
  22900. end: constant$1(35),
  22901. pageUp: constant$1(33),
  22902. pageDown: constant$1(34)
  22903. };
  22904. const createBespokeNumberInput = (editor, backstage, spec) => {
  22905. let currentComp = Optional.none();
  22906. const getValueFromCurrentComp = comp => comp.map(alloyComp => Representing.getValue(alloyComp)).getOr('');
  22907. const onSetup = onSetupEvent(editor, 'NodeChange SwitchMode', api => {
  22908. const comp = api.getComponent();
  22909. currentComp = Optional.some(comp);
  22910. spec.updateInputValue(comp);
  22911. Disabling.set(comp, !editor.selection.isEditable());
  22912. });
  22913. const getApi = comp => ({ getComponent: constant$1(comp) });
  22914. const editorOffCell = Cell(noop);
  22915. const customEvents = generate$6('custom-number-input-events');
  22916. const changeValue = (f, fromInput, focusBack) => {
  22917. const text = getValueFromCurrentComp(currentComp);
  22918. const newValue = spec.getNewValue(text, f);
  22919. const lenghtDelta = text.length - `${ newValue }`.length;
  22920. const oldStart = currentComp.map(comp => comp.element.dom.selectionStart - lenghtDelta);
  22921. const oldEnd = currentComp.map(comp => comp.element.dom.selectionEnd - lenghtDelta);
  22922. spec.onAction(newValue, focusBack);
  22923. currentComp.each(comp => {
  22924. Representing.setValue(comp, newValue);
  22925. if (fromInput) {
  22926. oldStart.each(oldStart => comp.element.dom.selectionStart = oldStart);
  22927. oldEnd.each(oldEnd => comp.element.dom.selectionEnd = oldEnd);
  22928. }
  22929. });
  22930. };
  22931. const decrease = (fromInput, focusBack) => changeValue((n, s) => n - s, fromInput, focusBack);
  22932. const increase = (fromInput, focusBack) => changeValue((n, s) => n + s, fromInput, focusBack);
  22933. const goToParent = comp => parentElement(comp.element).fold(Optional.none, parent => {
  22934. focus$3(parent);
  22935. return Optional.some(true);
  22936. });
  22937. const focusInput = comp => {
  22938. if (hasFocus(comp.element)) {
  22939. firstChild(comp.element).each(input => focus$3(input));
  22940. return Optional.some(true);
  22941. } else {
  22942. return Optional.none();
  22943. }
  22944. };
  22945. const makeStepperButton = (action, title, tooltip, classes) => {
  22946. const editorOffCellStepButton = Cell(noop);
  22947. const translatedTooltip = backstage.shared.providers.translate(tooltip);
  22948. const altExecuting = generate$6('altExecuting');
  22949. const onSetup = onSetupEvent(editor, 'NodeChange SwitchMode', api => {
  22950. Disabling.set(api.getComponent(), !editor.selection.isEditable());
  22951. });
  22952. const onClick = comp => {
  22953. if (!Disabling.isDisabled(comp)) {
  22954. action(true);
  22955. }
  22956. };
  22957. return Button.sketch({
  22958. dom: {
  22959. tag: 'button',
  22960. attributes: {
  22961. 'title': translatedTooltip,
  22962. 'aria-label': translatedTooltip
  22963. },
  22964. classes: classes.concat(title)
  22965. },
  22966. components: [renderIconFromPack$1(title, backstage.shared.providers.icons)],
  22967. buttonBehaviours: derive$1([
  22968. Disabling.config({}),
  22969. config(altExecuting, [
  22970. onControlAttached({
  22971. onSetup,
  22972. getApi
  22973. }, editorOffCellStepButton),
  22974. onControlDetached({ getApi }, editorOffCellStepButton),
  22975. run$1(keydown(), (comp, se) => {
  22976. if (se.event.raw.keyCode === Keys.space() || se.event.raw.keyCode === Keys.enter()) {
  22977. if (!Disabling.isDisabled(comp)) {
  22978. action(false);
  22979. }
  22980. }
  22981. }),
  22982. run$1(click(), onClick),
  22983. run$1(touchend(), onClick)
  22984. ])
  22985. ]),
  22986. eventOrder: {
  22987. [keydown()]: [
  22988. altExecuting,
  22989. 'keying'
  22990. ],
  22991. [click()]: [
  22992. altExecuting,
  22993. 'alloy.base.behaviour'
  22994. ],
  22995. [touchend()]: [
  22996. altExecuting,
  22997. 'alloy.base.behaviour'
  22998. ]
  22999. }
  23000. });
  23001. };
  23002. const memMinus = record(makeStepperButton(focusBack => decrease(false, focusBack), 'minus', 'Decrease font size', []));
  23003. const memPlus = record(makeStepperButton(focusBack => increase(false, focusBack), 'plus', 'Increase font size', []));
  23004. const memInput = record({
  23005. dom: {
  23006. tag: 'div',
  23007. classes: ['tox-input-wrapper']
  23008. },
  23009. components: [Input.sketch({
  23010. inputBehaviours: derive$1([
  23011. Disabling.config({}),
  23012. config(customEvents, [
  23013. onControlAttached({
  23014. onSetup,
  23015. getApi
  23016. }, editorOffCell),
  23017. onControlDetached({ getApi }, editorOffCell)
  23018. ]),
  23019. config('input-update-display-text', [
  23020. run$1(updateMenuText, (comp, se) => {
  23021. Representing.setValue(comp, se.event.text);
  23022. }),
  23023. run$1(focusout(), comp => {
  23024. spec.onAction(Representing.getValue(comp));
  23025. }),
  23026. run$1(change(), comp => {
  23027. spec.onAction(Representing.getValue(comp));
  23028. })
  23029. ]),
  23030. Keying.config({
  23031. mode: 'special',
  23032. onEnter: _comp => {
  23033. changeValue(identity, true, true);
  23034. return Optional.some(true);
  23035. },
  23036. onEscape: goToParent,
  23037. onUp: _comp => {
  23038. increase(true, false);
  23039. return Optional.some(true);
  23040. },
  23041. onDown: _comp => {
  23042. decrease(true, false);
  23043. return Optional.some(true);
  23044. },
  23045. onLeft: (_comp, se) => {
  23046. se.cut();
  23047. return Optional.none();
  23048. },
  23049. onRight: (_comp, se) => {
  23050. se.cut();
  23051. return Optional.none();
  23052. }
  23053. })
  23054. ])
  23055. })],
  23056. behaviours: derive$1([
  23057. Focusing.config({}),
  23058. Keying.config({
  23059. mode: 'special',
  23060. onEnter: focusInput,
  23061. onSpace: focusInput,
  23062. onEscape: goToParent
  23063. }),
  23064. config('input-wrapper-events', [run$1(mouseover(), comp => {
  23065. each$1([
  23066. memMinus,
  23067. memPlus
  23068. ], button => {
  23069. const buttonNode = SugarElement.fromDom(button.get(comp).element.dom);
  23070. if (hasFocus(buttonNode)) {
  23071. blur$1(buttonNode);
  23072. }
  23073. });
  23074. })])
  23075. ])
  23076. });
  23077. return {
  23078. dom: {
  23079. tag: 'div',
  23080. classes: ['tox-number-input']
  23081. },
  23082. components: [
  23083. memMinus.asSpec(),
  23084. memInput.asSpec(),
  23085. memPlus.asSpec()
  23086. ],
  23087. behaviours: derive$1([
  23088. Focusing.config({}),
  23089. Keying.config({
  23090. mode: 'flow',
  23091. focusInside: FocusInsideModes.OnEnterOrSpaceMode,
  23092. cycles: false,
  23093. selector: 'button, .tox-input-wrapper',
  23094. onEscape: wrapperComp => {
  23095. if (hasFocus(wrapperComp.element)) {
  23096. return Optional.none();
  23097. } else {
  23098. focus$3(wrapperComp.element);
  23099. return Optional.some(true);
  23100. }
  23101. }
  23102. })
  23103. ])
  23104. };
  23105. };
  23106. const menuTitle$1 = 'Font sizes';
  23107. const btnTooltip$1 = 'Font size {0}';
  23108. const fallbackFontSize = '12pt';
  23109. const legacyFontSizes = {
  23110. '8pt': '1',
  23111. '10pt': '2',
  23112. '12pt': '3',
  23113. '14pt': '4',
  23114. '18pt': '5',
  23115. '24pt': '6',
  23116. '36pt': '7'
  23117. };
  23118. const keywordFontSizes = {
  23119. 'xx-small': '7pt',
  23120. 'x-small': '8pt',
  23121. 'small': '10pt',
  23122. 'medium': '12pt',
  23123. 'large': '14pt',
  23124. 'x-large': '18pt',
  23125. 'xx-large': '24pt'
  23126. };
  23127. const round = (number, precision) => {
  23128. const factor = Math.pow(10, precision);
  23129. return Math.round(number * factor) / factor;
  23130. };
  23131. const toPt = (fontSize, precision) => {
  23132. if (/[0-9.]+px$/.test(fontSize)) {
  23133. return round(parseInt(fontSize, 10) * 72 / 96, precision || 0) + 'pt';
  23134. } else {
  23135. return get$g(keywordFontSizes, fontSize).getOr(fontSize);
  23136. }
  23137. };
  23138. const toLegacy = fontSize => get$g(legacyFontSizes, fontSize).getOr('');
  23139. const getSpec$1 = editor => {
  23140. const getMatchingValue = () => {
  23141. let matchOpt = Optional.none();
  23142. const items = dataset.data;
  23143. const fontSize = editor.queryCommandValue('FontSize');
  23144. if (fontSize) {
  23145. for (let precision = 3; matchOpt.isNone() && precision >= 0; precision--) {
  23146. const pt = toPt(fontSize, precision);
  23147. const legacy = toLegacy(pt);
  23148. matchOpt = find$5(items, item => item.format === fontSize || item.format === pt || item.format === legacy);
  23149. }
  23150. }
  23151. return {
  23152. matchOpt,
  23153. size: fontSize
  23154. };
  23155. };
  23156. const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
  23157. const getCurrentValue = () => {
  23158. const {matchOpt} = getMatchingValue();
  23159. return matchOpt;
  23160. };
  23161. const getPreviewFor = constant$1(Optional.none);
  23162. const onAction = rawItem => () => {
  23163. editor.undoManager.transact(() => {
  23164. editor.focus();
  23165. editor.execCommand('FontSize', false, rawItem.format);
  23166. });
  23167. };
  23168. const updateSelectMenuText = comp => {
  23169. const {matchOpt, size} = getMatchingValue();
  23170. const text = matchOpt.fold(constant$1(size), match => match.title);
  23171. emitWith(comp, updateMenuText, { text });
  23172. fireFontSizeTextUpdate(editor, { value: text });
  23173. };
  23174. const dataset = buildBasicSettingsDataset(editor, 'font_size_formats', Delimiter.Space);
  23175. return {
  23176. tooltip: makeTooltipText(editor, btnTooltip$1, fallbackFontSize),
  23177. text: Optional.some(fallbackFontSize),
  23178. icon: Optional.none(),
  23179. isSelectedFor,
  23180. getPreviewFor,
  23181. getCurrentValue,
  23182. onAction,
  23183. updateText: updateSelectMenuText,
  23184. dataset,
  23185. shouldHide: false,
  23186. isInvalid: never
  23187. };
  23188. };
  23189. const createFontSizeButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$1(editor), btnTooltip$1, 'FontSizeTextUpdate');
  23190. const getConfigFromUnit = unit => {
  23191. var _a;
  23192. const baseConfig = { step: 1 };
  23193. const configs = {
  23194. em: { step: 0.1 },
  23195. cm: { step: 0.1 },
  23196. in: { step: 0.1 },
  23197. pc: { step: 0.1 },
  23198. ch: { step: 0.1 },
  23199. rem: { step: 0.1 }
  23200. };
  23201. return (_a = configs[unit]) !== null && _a !== void 0 ? _a : baseConfig;
  23202. };
  23203. const defaultValue = 16;
  23204. const isValidValue = value => value >= 0;
  23205. const getNumberInputSpec = editor => {
  23206. const getCurrentValue = () => editor.queryCommandValue('FontSize');
  23207. const updateInputValue = comp => emitWith(comp, updateMenuText, { text: getCurrentValue() });
  23208. return {
  23209. updateInputValue,
  23210. onAction: (format, focusBack) => editor.execCommand('FontSize', false, format, { skip_focus: !focusBack }),
  23211. getNewValue: (text, updateFunction) => {
  23212. parse(text, [
  23213. 'unsupportedLength',
  23214. 'empty'
  23215. ]);
  23216. const currentValue = getCurrentValue();
  23217. const parsedText = parse(text, [
  23218. 'unsupportedLength',
  23219. 'empty'
  23220. ]).or(parse(currentValue, [
  23221. 'unsupportedLength',
  23222. 'empty'
  23223. ]));
  23224. const value = parsedText.map(res => res.value).getOr(defaultValue);
  23225. const defaultUnit = getFontSizeInputDefaultUnit(editor);
  23226. const unit = parsedText.map(res => res.unit).filter(u => u !== '').getOr(defaultUnit);
  23227. const newValue = updateFunction(value, getConfigFromUnit(unit).step);
  23228. const res = `${ isValidValue(newValue) ? newValue : value }${ unit }`;
  23229. if (res !== currentValue) {
  23230. fireFontSizeInputTextUpdate(editor, { value: res });
  23231. }
  23232. return res;
  23233. }
  23234. };
  23235. };
  23236. const createFontSizeInputButton = (editor, backstage) => createBespokeNumberInput(editor, backstage, getNumberInputSpec(editor));
  23237. const createFontSizeMenu = (editor, backstage) => {
  23238. const menuItems = createMenuItems(editor, backstage, getSpec$1(editor));
  23239. editor.ui.registry.addNestedMenuItem('fontsize', {
  23240. text: menuTitle$1,
  23241. onSetup: onSetupEditableToggle(editor),
  23242. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  23243. });
  23244. };
  23245. const menuTitle = 'Formats';
  23246. const btnTooltip = 'Format {0}';
  23247. const getSpec = (editor, dataset) => {
  23248. const fallbackFormat = 'Paragraph';
  23249. const isSelectedFor = format => () => editor.formatter.match(format);
  23250. const getPreviewFor = format => () => {
  23251. const fmt = editor.formatter.get(format);
  23252. return fmt !== undefined ? Optional.some({
  23253. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  23254. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  23255. }) : Optional.none();
  23256. };
  23257. const updateSelectMenuText = comp => {
  23258. const getFormatItems = fmt => {
  23259. if (isNestedFormat(fmt)) {
  23260. return bind$3(fmt.items, getFormatItems);
  23261. } else if (isFormatReference(fmt)) {
  23262. return [{
  23263. title: fmt.title,
  23264. format: fmt.format
  23265. }];
  23266. } else {
  23267. return [];
  23268. }
  23269. };
  23270. const flattenedItems = bind$3(getStyleFormats(editor), getFormatItems);
  23271. const detectedFormat = findNearest(editor, constant$1(flattenedItems));
  23272. const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
  23273. emitWith(comp, updateMenuText, { text });
  23274. fireStylesTextUpdate(editor, { value: text });
  23275. };
  23276. return {
  23277. tooltip: makeTooltipText(editor, btnTooltip, fallbackFormat),
  23278. text: Optional.some(fallbackFormat),
  23279. icon: Optional.none(),
  23280. isSelectedFor,
  23281. getCurrentValue: Optional.none,
  23282. getPreviewFor,
  23283. onAction: onActionToggleFormat$1(editor),
  23284. updateText: updateSelectMenuText,
  23285. shouldHide: shouldAutoHideStyleFormats(editor),
  23286. isInvalid: item => !editor.formatter.canApply(item.format),
  23287. dataset
  23288. };
  23289. };
  23290. const createStylesButton = (editor, backstage) => {
  23291. const dataset = {
  23292. type: 'advanced',
  23293. ...backstage.styles
  23294. };
  23295. return createSelectButton(editor, backstage, getSpec(editor, dataset), btnTooltip, 'StylesTextUpdate');
  23296. };
  23297. const createStylesMenu = (editor, backstage) => {
  23298. const dataset = {
  23299. type: 'advanced',
  23300. ...backstage.styles
  23301. };
  23302. const menuItems = createMenuItems(editor, backstage, getSpec(editor, dataset));
  23303. editor.ui.registry.addNestedMenuItem('styles', {
  23304. text: menuTitle,
  23305. onSetup: onSetupEditableToggle(editor),
  23306. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  23307. });
  23308. };
  23309. const schema$7 = constant$1([
  23310. required$1('toggleClass'),
  23311. required$1('fetch'),
  23312. onStrictHandler('onExecute'),
  23313. defaulted('getHotspot', Optional.some),
  23314. defaulted('getAnchorOverrides', constant$1({})),
  23315. schema$y(),
  23316. onStrictHandler('onItemExecute'),
  23317. option$3('lazySink'),
  23318. required$1('dom'),
  23319. onHandler('onOpen'),
  23320. field('splitDropdownBehaviours', [
  23321. Coupling,
  23322. Keying,
  23323. Focusing
  23324. ]),
  23325. defaulted('matchWidth', false),
  23326. defaulted('useMinWidth', false),
  23327. defaulted('eventOrder', {}),
  23328. option$3('role')
  23329. ].concat(sandboxFields()));
  23330. const arrowPart = required({
  23331. factory: Button,
  23332. schema: [required$1('dom')],
  23333. name: 'arrow',
  23334. defaults: () => {
  23335. return { buttonBehaviours: derive$1([Focusing.revoke()]) };
  23336. },
  23337. overrides: detail => {
  23338. return {
  23339. dom: {
  23340. tag: 'span',
  23341. attributes: { role: 'presentation' }
  23342. },
  23343. action: arrow => {
  23344. arrow.getSystem().getByUid(detail.uid).each(emitExecute);
  23345. },
  23346. buttonBehaviours: derive$1([Toggling.config({
  23347. toggleOnExecute: false,
  23348. toggleClass: detail.toggleClass
  23349. })])
  23350. };
  23351. }
  23352. });
  23353. const buttonPart = required({
  23354. factory: Button,
  23355. schema: [required$1('dom')],
  23356. name: 'button',
  23357. defaults: () => {
  23358. return { buttonBehaviours: derive$1([Focusing.revoke()]) };
  23359. },
  23360. overrides: detail => {
  23361. return {
  23362. dom: {
  23363. tag: 'span',
  23364. attributes: { role: 'presentation' }
  23365. },
  23366. action: btn => {
  23367. btn.getSystem().getByUid(detail.uid).each(splitDropdown => {
  23368. detail.onExecute(splitDropdown, btn);
  23369. });
  23370. }
  23371. };
  23372. }
  23373. });
  23374. const parts$3 = constant$1([
  23375. arrowPart,
  23376. buttonPart,
  23377. optional({
  23378. factory: {
  23379. sketch: spec => {
  23380. return {
  23381. uid: spec.uid,
  23382. dom: {
  23383. tag: 'span',
  23384. styles: { display: 'none' },
  23385. attributes: { 'aria-hidden': 'true' },
  23386. innerHtml: spec.text
  23387. }
  23388. };
  23389. }
  23390. },
  23391. schema: [required$1('text')],
  23392. name: 'aria-descriptor'
  23393. }),
  23394. external({
  23395. schema: [tieredMenuMarkers()],
  23396. name: 'menu',
  23397. defaults: detail => {
  23398. return {
  23399. onExecute: (tmenu, item) => {
  23400. tmenu.getSystem().getByUid(detail.uid).each(splitDropdown => {
  23401. detail.onItemExecute(splitDropdown, tmenu, item);
  23402. });
  23403. }
  23404. };
  23405. }
  23406. }),
  23407. partType$1()
  23408. ]);
  23409. const factory$5 = (detail, components, spec, externals) => {
  23410. const switchToMenu = sandbox => {
  23411. Composing.getCurrent(sandbox).each(current => {
  23412. Highlighting.highlightFirst(current);
  23413. Keying.focusIn(current);
  23414. });
  23415. };
  23416. const action = component => {
  23417. const onOpenSync = switchToMenu;
  23418. togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightMenuAndItem).get(noop);
  23419. };
  23420. const openMenu = comp => {
  23421. action(comp);
  23422. return Optional.some(true);
  23423. };
  23424. const executeOnButton = comp => {
  23425. const button = getPartOrDie(comp, detail, 'button');
  23426. emitExecute(button);
  23427. return Optional.some(true);
  23428. };
  23429. const buttonEvents = {
  23430. ...derive$2([runOnAttached((component, _simulatedEvent) => {
  23431. const ariaDescriptor = getPart(component, detail, 'aria-descriptor');
  23432. ariaDescriptor.each(descriptor => {
  23433. const descriptorId = generate$6('aria');
  23434. set$9(descriptor.element, 'id', descriptorId);
  23435. set$9(component.element, 'aria-describedby', descriptorId);
  23436. });
  23437. })]),
  23438. ...events$a(Optional.some(action))
  23439. };
  23440. const apis = {
  23441. repositionMenus: comp => {
  23442. if (Toggling.isOn(comp)) {
  23443. repositionMenus(comp);
  23444. }
  23445. }
  23446. };
  23447. return {
  23448. uid: detail.uid,
  23449. dom: detail.dom,
  23450. components,
  23451. apis,
  23452. eventOrder: {
  23453. ...detail.eventOrder,
  23454. [execute$5()]: [
  23455. 'disabling',
  23456. 'toggling',
  23457. 'alloy.base.behaviour'
  23458. ]
  23459. },
  23460. events: buttonEvents,
  23461. behaviours: augment(detail.splitDropdownBehaviours, [
  23462. Coupling.config({
  23463. others: {
  23464. sandbox: hotspot => {
  23465. const arrow = getPartOrDie(hotspot, detail, 'arrow');
  23466. const extras = {
  23467. onOpen: () => {
  23468. Toggling.on(arrow);
  23469. Toggling.on(hotspot);
  23470. },
  23471. onClose: () => {
  23472. Toggling.off(arrow);
  23473. Toggling.off(hotspot);
  23474. }
  23475. };
  23476. return makeSandbox$1(detail, hotspot, extras);
  23477. }
  23478. }
  23479. }),
  23480. Keying.config({
  23481. mode: 'special',
  23482. onSpace: executeOnButton,
  23483. onEnter: executeOnButton,
  23484. onDown: openMenu
  23485. }),
  23486. Focusing.config({}),
  23487. Toggling.config({
  23488. toggleOnExecute: false,
  23489. aria: { mode: 'expanded' }
  23490. })
  23491. ]),
  23492. domModification: {
  23493. attributes: {
  23494. 'role': detail.role.getOr('button'),
  23495. 'aria-haspopup': true
  23496. }
  23497. }
  23498. };
  23499. };
  23500. const SplitDropdown = composite({
  23501. name: 'SplitDropdown',
  23502. configFields: schema$7(),
  23503. partFields: parts$3(),
  23504. factory: factory$5,
  23505. apis: { repositionMenus: (apis, comp) => apis.repositionMenus(comp) }
  23506. });
  23507. const getButtonApi = component => ({
  23508. isEnabled: () => !Disabling.isDisabled(component),
  23509. setEnabled: state => Disabling.set(component, !state),
  23510. setText: text => emitWith(component, updateMenuText, { text }),
  23511. setIcon: icon => emitWith(component, updateMenuIcon, { icon })
  23512. });
  23513. const getToggleApi = component => ({
  23514. setActive: state => {
  23515. Toggling.set(component, state);
  23516. },
  23517. isActive: () => Toggling.isOn(component),
  23518. isEnabled: () => !Disabling.isDisabled(component),
  23519. setEnabled: state => Disabling.set(component, !state),
  23520. setText: text => emitWith(component, updateMenuText, { text }),
  23521. setIcon: icon => emitWith(component, updateMenuIcon, { icon })
  23522. });
  23523. const getTooltipAttributes = (tooltip, providersBackstage) => tooltip.map(tooltip => ({
  23524. 'aria-label': providersBackstage.translate(tooltip),
  23525. 'title': providersBackstage.translate(tooltip)
  23526. })).getOr({});
  23527. const focusButtonEvent = generate$6('focus-button');
  23528. const renderCommonStructure = (optIcon, optText, tooltip, behaviours, providersBackstage) => {
  23529. const optMemDisplayText = optText.map(text => record(renderLabel$1(text, 'tox-tbtn', providersBackstage)));
  23530. const optMemDisplayIcon = optIcon.map(icon => record(renderReplaceableIconFromPack(icon, providersBackstage.icons)));
  23531. return {
  23532. dom: {
  23533. tag: 'button',
  23534. classes: ['tox-tbtn'].concat(optText.isSome() ? ['tox-tbtn--select'] : []),
  23535. attributes: getTooltipAttributes(tooltip, providersBackstage)
  23536. },
  23537. components: componentRenderPipeline([
  23538. optMemDisplayIcon.map(mem => mem.asSpec()),
  23539. optMemDisplayText.map(mem => mem.asSpec())
  23540. ]),
  23541. eventOrder: {
  23542. [mousedown()]: [
  23543. 'focusing',
  23544. 'alloy.base.behaviour',
  23545. commonButtonDisplayEvent
  23546. ],
  23547. [attachedToDom()]: [
  23548. commonButtonDisplayEvent,
  23549. 'toolbar-group-button-events'
  23550. ]
  23551. },
  23552. buttonBehaviours: derive$1([
  23553. DisablingConfigs.toolbarButton(providersBackstage.isDisabled),
  23554. receivingConfig(),
  23555. config(commonButtonDisplayEvent, [
  23556. runOnAttached((comp, _se) => forceInitialSize(comp)),
  23557. run$1(updateMenuText, (comp, se) => {
  23558. optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
  23559. Replacing.set(displayText, [text$2(providersBackstage.translate(se.event.text))]);
  23560. });
  23561. }),
  23562. run$1(updateMenuIcon, (comp, se) => {
  23563. optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
  23564. Replacing.set(displayIcon, [renderReplaceableIconFromPack(se.event.icon, providersBackstage.icons)]);
  23565. });
  23566. }),
  23567. run$1(mousedown(), (button, se) => {
  23568. se.event.prevent();
  23569. emit(button, focusButtonEvent);
  23570. })
  23571. ])
  23572. ].concat(behaviours.getOr([])))
  23573. };
  23574. };
  23575. const renderFloatingToolbarButton = (spec, backstage, identifyButtons, attributes) => {
  23576. const sharedBackstage = backstage.shared;
  23577. const editorOffCell = Cell(noop);
  23578. const specialisation = {
  23579. toolbarButtonBehaviours: [],
  23580. getApi: getButtonApi,
  23581. onSetup: spec.onSetup
  23582. };
  23583. const behaviours = [config('toolbar-group-button-events', [
  23584. onControlAttached(specialisation, editorOffCell),
  23585. onControlDetached(specialisation, editorOffCell)
  23586. ])];
  23587. return FloatingToolbarButton.sketch({
  23588. lazySink: sharedBackstage.getSink,
  23589. fetch: () => Future.nu(resolve => {
  23590. resolve(map$2(identifyButtons(spec.items), renderToolbarGroup));
  23591. }),
  23592. markers: { toggledClass: 'tox-tbtn--enabled' },
  23593. parts: {
  23594. button: renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.some(behaviours), sharedBackstage.providers),
  23595. toolbar: {
  23596. dom: {
  23597. tag: 'div',
  23598. classes: ['tox-toolbar__overflow'],
  23599. attributes
  23600. }
  23601. }
  23602. }
  23603. });
  23604. };
  23605. const renderCommonToolbarButton = (spec, specialisation, providersBackstage) => {
  23606. var _d;
  23607. const editorOffCell = Cell(noop);
  23608. const structure = renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), providersBackstage);
  23609. return Button.sketch({
  23610. dom: structure.dom,
  23611. components: structure.components,
  23612. eventOrder: toolbarButtonEventOrder,
  23613. buttonBehaviours: {
  23614. ...derive$1([
  23615. config('toolbar-button-events', [
  23616. onToolbarButtonExecute({
  23617. onAction: spec.onAction,
  23618. getApi: specialisation.getApi
  23619. }),
  23620. onControlAttached(specialisation, editorOffCell),
  23621. onControlDetached(specialisation, editorOffCell)
  23622. ]),
  23623. DisablingConfigs.toolbarButton(() => !spec.enabled || providersBackstage.isDisabled()),
  23624. receivingConfig()
  23625. ].concat(specialisation.toolbarButtonBehaviours)),
  23626. [commonButtonDisplayEvent]: (_d = structure.buttonBehaviours) === null || _d === void 0 ? void 0 : _d[commonButtonDisplayEvent]
  23627. }
  23628. });
  23629. };
  23630. const renderToolbarButton = (spec, providersBackstage) => renderToolbarButtonWith(spec, providersBackstage, []);
  23631. const renderToolbarButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
  23632. toolbarButtonBehaviours: bonusEvents.length > 0 ? [config('toolbarButtonWith', bonusEvents)] : [],
  23633. getApi: getButtonApi,
  23634. onSetup: spec.onSetup
  23635. }, providersBackstage);
  23636. const renderToolbarToggleButton = (spec, providersBackstage) => renderToolbarToggleButtonWith(spec, providersBackstage, []);
  23637. const renderToolbarToggleButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
  23638. toolbarButtonBehaviours: [
  23639. Replacing.config({}),
  23640. Toggling.config({
  23641. toggleClass: 'tox-tbtn--enabled',
  23642. aria: { mode: 'pressed' },
  23643. toggleOnExecute: false
  23644. })
  23645. ].concat(bonusEvents.length > 0 ? [config('toolbarToggleButtonWith', bonusEvents)] : []),
  23646. getApi: getToggleApi,
  23647. onSetup: spec.onSetup
  23648. }, providersBackstage);
  23649. const fetchChoices = (getApi, spec, providersBackstage) => comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
  23650. spec.onItemAction(getApi(comp), value);
  23651. }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), providersBackstage), {
  23652. movement: deriveMenuMovement(spec.columns, spec.presets),
  23653. menuBehaviours: SimpleBehaviours.unnamedEvents(spec.columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
  23654. detectSize(comp, 4, classForPreset(spec.presets)).each(({numRows, numColumns}) => {
  23655. Keying.setGridSize(comp, numRows, numColumns);
  23656. });
  23657. })])
  23658. }))));
  23659. const renderSplitButton = (spec, sharedBackstage) => {
  23660. const getApi = comp => ({
  23661. isEnabled: () => !Disabling.isDisabled(comp),
  23662. setEnabled: state => Disabling.set(comp, !state),
  23663. setIconFill: (id, value) => {
  23664. descendant(comp.element, `svg path[class="${ id }"], rect[class="${ id }"]`).each(underlinePath => {
  23665. set$9(underlinePath, 'fill', value);
  23666. });
  23667. },
  23668. setActive: state => {
  23669. set$9(comp.element, 'aria-pressed', state);
  23670. descendant(comp.element, 'span').each(button => {
  23671. comp.getSystem().getByDom(button).each(buttonComp => Toggling.set(buttonComp, state));
  23672. });
  23673. },
  23674. isActive: () => descendant(comp.element, 'span').exists(button => comp.getSystem().getByDom(button).exists(Toggling.isOn)),
  23675. setText: text => descendant(comp.element, 'span').each(button => comp.getSystem().getByDom(button).each(buttonComp => emitWith(buttonComp, updateMenuText, { text }))),
  23676. setIcon: icon => descendant(comp.element, 'span').each(button => comp.getSystem().getByDom(button).each(buttonComp => emitWith(buttonComp, updateMenuIcon, { icon }))),
  23677. setTooltip: tooltip => {
  23678. const translatedTooltip = sharedBackstage.providers.translate(tooltip);
  23679. setAll$1(comp.element, {
  23680. 'aria-label': translatedTooltip,
  23681. 'title': translatedTooltip
  23682. });
  23683. }
  23684. });
  23685. const editorOffCell = Cell(noop);
  23686. const specialisation = {
  23687. getApi,
  23688. onSetup: spec.onSetup
  23689. };
  23690. return SplitDropdown.sketch({
  23691. dom: {
  23692. tag: 'div',
  23693. classes: ['tox-split-button'],
  23694. attributes: {
  23695. 'aria-pressed': false,
  23696. ...getTooltipAttributes(spec.tooltip, sharedBackstage.providers)
  23697. }
  23698. },
  23699. onExecute: button => {
  23700. const api = getApi(button);
  23701. if (api.isEnabled()) {
  23702. spec.onAction(api);
  23703. }
  23704. },
  23705. onItemExecute: (_a, _b, _c) => {
  23706. },
  23707. splitDropdownBehaviours: derive$1([
  23708. DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
  23709. receivingConfig(),
  23710. config('split-dropdown-events', [
  23711. runOnAttached((comp, _se) => forceInitialSize(comp)),
  23712. run$1(focusButtonEvent, Focusing.focus),
  23713. onControlAttached(specialisation, editorOffCell),
  23714. onControlDetached(specialisation, editorOffCell)
  23715. ]),
  23716. Unselecting.config({})
  23717. ]),
  23718. eventOrder: {
  23719. [attachedToDom()]: [
  23720. 'alloy.base.behaviour',
  23721. 'split-dropdown-events'
  23722. ]
  23723. },
  23724. toggleClass: 'tox-tbtn--enabled',
  23725. lazySink: sharedBackstage.getSink,
  23726. fetch: fetchChoices(getApi, spec, sharedBackstage.providers),
  23727. parts: { menu: part(false, spec.columns, spec.presets) },
  23728. components: [
  23729. SplitDropdown.parts.button(renderCommonStructure(spec.icon, spec.text, Optional.none(), Optional.some([Toggling.config({
  23730. toggleClass: 'tox-tbtn--enabled',
  23731. toggleOnExecute: false
  23732. })]), sharedBackstage.providers)),
  23733. SplitDropdown.parts.arrow({
  23734. dom: {
  23735. tag: 'button',
  23736. classes: [
  23737. 'tox-tbtn',
  23738. 'tox-split-button__chevron'
  23739. ],
  23740. innerHtml: get$2('chevron-down', sharedBackstage.providers.icons)
  23741. },
  23742. buttonBehaviours: derive$1([
  23743. DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
  23744. receivingConfig(),
  23745. addFocusableBehaviour()
  23746. ])
  23747. }),
  23748. SplitDropdown.parts['aria-descriptor']({ text: sharedBackstage.providers.translate('To open the popup, press Shift+Enter') })
  23749. ]
  23750. });
  23751. };
  23752. const defaultToolbar = [
  23753. {
  23754. name: 'history',
  23755. items: [
  23756. 'undo',
  23757. 'redo'
  23758. ]
  23759. },
  23760. {
  23761. name: 'ai',
  23762. items: [
  23763. 'aidialog',
  23764. 'aishortcuts'
  23765. ]
  23766. },
  23767. {
  23768. name: 'styles',
  23769. items: ['styles']
  23770. },
  23771. {
  23772. name: 'formatting',
  23773. items: [
  23774. 'bold',
  23775. 'italic'
  23776. ]
  23777. },
  23778. {
  23779. name: 'alignment',
  23780. items: [
  23781. 'alignleft',
  23782. 'aligncenter',
  23783. 'alignright',
  23784. 'alignjustify'
  23785. ]
  23786. },
  23787. {
  23788. name: 'indentation',
  23789. items: [
  23790. 'outdent',
  23791. 'indent'
  23792. ]
  23793. },
  23794. {
  23795. name: 'permanent pen',
  23796. items: ['permanentpen']
  23797. },
  23798. {
  23799. name: 'comments',
  23800. items: ['addcomment']
  23801. }
  23802. ];
  23803. const renderFromBridge = (bridgeBuilder, render) => (spec, backstage, editor) => {
  23804. const internal = bridgeBuilder(spec).mapError(errInfo => formatError(errInfo)).getOrDie();
  23805. return render(internal, backstage, editor);
  23806. };
  23807. const types = {
  23808. button: renderFromBridge(createToolbarButton, (s, backstage) => renderToolbarButton(s, backstage.shared.providers)),
  23809. togglebutton: renderFromBridge(createToggleButton, (s, backstage) => renderToolbarToggleButton(s, backstage.shared.providers)),
  23810. menubutton: renderFromBridge(createMenuButton, (s, backstage) => renderMenuButton(s, 'tox-tbtn', backstage, Optional.none(), false)),
  23811. splitbutton: renderFromBridge(createSplitButton, (s, backstage) => renderSplitButton(s, backstage.shared)),
  23812. grouptoolbarbutton: renderFromBridge(createGroupToolbarButton, (s, backstage, editor) => {
  23813. const buttons = editor.ui.registry.getAll().buttons;
  23814. const identify = toolbar => identifyButtons(editor, {
  23815. buttons,
  23816. toolbar,
  23817. allowToolbarGroups: false
  23818. }, backstage, Optional.none());
  23819. const attributes = { [Attribute]: backstage.shared.header.isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop };
  23820. switch (getToolbarMode(editor)) {
  23821. case ToolbarMode$1.floating:
  23822. return renderFloatingToolbarButton(s, backstage, identify, attributes);
  23823. default:
  23824. throw new Error('Toolbar groups are only supported when using floating toolbar mode');
  23825. }
  23826. })
  23827. };
  23828. const extractFrom = (spec, backstage, editor) => get$g(types, spec.type).fold(() => {
  23829. console.error('skipping button defined by', spec);
  23830. return Optional.none();
  23831. }, render => Optional.some(render(spec, backstage, editor)));
  23832. const bespokeButtons = {
  23833. styles: createStylesButton,
  23834. fontsize: createFontSizeButton,
  23835. fontsizeinput: createFontSizeInputButton,
  23836. fontfamily: createFontFamilyButton,
  23837. blocks: createBlocksButton,
  23838. align: createAlignButton
  23839. };
  23840. const removeUnusedDefaults = buttons => {
  23841. const filteredItemGroups = map$2(defaultToolbar, group => {
  23842. const items = filter$2(group.items, subItem => has$2(buttons, subItem) || has$2(bespokeButtons, subItem));
  23843. return {
  23844. name: group.name,
  23845. items
  23846. };
  23847. });
  23848. return filter$2(filteredItemGroups, group => group.items.length > 0);
  23849. };
  23850. const convertStringToolbar = strToolbar => {
  23851. const groupsStrings = strToolbar.split('|');
  23852. return map$2(groupsStrings, g => ({ items: g.trim().split(' ') }));
  23853. };
  23854. const isToolbarGroupSettingArray = toolbar => isArrayOf(toolbar, t => has$2(t, 'name') && has$2(t, 'items'));
  23855. const createToolbar = toolbarConfig => {
  23856. const toolbar = toolbarConfig.toolbar;
  23857. const buttons = toolbarConfig.buttons;
  23858. if (toolbar === false) {
  23859. return [];
  23860. } else if (toolbar === undefined || toolbar === true) {
  23861. return removeUnusedDefaults(buttons);
  23862. } else if (isString(toolbar)) {
  23863. return convertStringToolbar(toolbar);
  23864. } else if (isToolbarGroupSettingArray(toolbar)) {
  23865. return toolbar;
  23866. } else {
  23867. console.error('Toolbar type should be string, string[], boolean or ToolbarGroup[]');
  23868. return [];
  23869. }
  23870. };
  23871. const lookupButton = (editor, buttons, toolbarItem, allowToolbarGroups, backstage, prefixes) => get$g(buttons, toolbarItem.toLowerCase()).orThunk(() => prefixes.bind(ps => findMap(ps, prefix => get$g(buttons, prefix + toolbarItem.toLowerCase())))).fold(() => get$g(bespokeButtons, toolbarItem.toLowerCase()).map(r => r(editor, backstage)), spec => {
  23872. if (spec.type === 'grouptoolbarbutton' && !allowToolbarGroups) {
  23873. console.warn(`Ignoring the '${ toolbarItem }' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`);
  23874. return Optional.none();
  23875. } else {
  23876. return extractFrom(spec, backstage, editor);
  23877. }
  23878. });
  23879. const identifyButtons = (editor, toolbarConfig, backstage, prefixes) => {
  23880. const toolbarGroups = createToolbar(toolbarConfig);
  23881. const groups = map$2(toolbarGroups, group => {
  23882. const items = bind$3(group.items, toolbarItem => {
  23883. return toolbarItem.trim().length === 0 ? [] : lookupButton(editor, toolbarConfig.buttons, toolbarItem, toolbarConfig.allowToolbarGroups, backstage, prefixes).toArray();
  23884. });
  23885. return {
  23886. title: Optional.from(editor.translate(group.name)),
  23887. items
  23888. };
  23889. });
  23890. return filter$2(groups, group => group.items.length > 0);
  23891. };
  23892. const setToolbar = (editor, uiRefs, rawUiConfig, backstage) => {
  23893. const outerContainer = uiRefs.mainUi.outerContainer;
  23894. const toolbarConfig = rawUiConfig.toolbar;
  23895. const toolbarButtonsConfig = rawUiConfig.buttons;
  23896. if (isArrayOf(toolbarConfig, isString)) {
  23897. const toolbars = toolbarConfig.map(t => {
  23898. const config = {
  23899. toolbar: t,
  23900. buttons: toolbarButtonsConfig,
  23901. allowToolbarGroups: rawUiConfig.allowToolbarGroups
  23902. };
  23903. return identifyButtons(editor, config, backstage, Optional.none());
  23904. });
  23905. OuterContainer.setToolbars(outerContainer, toolbars);
  23906. } else {
  23907. OuterContainer.setToolbar(outerContainer, identifyButtons(editor, rawUiConfig, backstage, Optional.none()));
  23908. }
  23909. };
  23910. const detection = detect$2();
  23911. const isiOS12 = detection.os.isiOS() && detection.os.version.major <= 12;
  23912. const setupEvents$1 = (editor, uiRefs) => {
  23913. const {uiMotherships} = uiRefs;
  23914. const dom = editor.dom;
  23915. let contentWindow = editor.getWin();
  23916. const initialDocEle = editor.getDoc().documentElement;
  23917. const lastWindowDimensions = Cell(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
  23918. const lastDocumentDimensions = Cell(SugarPosition(initialDocEle.offsetWidth, initialDocEle.offsetHeight));
  23919. const resizeWindow = () => {
  23920. const outer = lastWindowDimensions.get();
  23921. if (outer.left !== contentWindow.innerWidth || outer.top !== contentWindow.innerHeight) {
  23922. lastWindowDimensions.set(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
  23923. fireResizeContent(editor);
  23924. }
  23925. };
  23926. const resizeDocument = () => {
  23927. const docEle = editor.getDoc().documentElement;
  23928. const inner = lastDocumentDimensions.get();
  23929. if (inner.left !== docEle.offsetWidth || inner.top !== docEle.offsetHeight) {
  23930. lastDocumentDimensions.set(SugarPosition(docEle.offsetWidth, docEle.offsetHeight));
  23931. fireResizeContent(editor);
  23932. }
  23933. };
  23934. const scroll = e => {
  23935. fireScrollContent(editor, e);
  23936. };
  23937. dom.bind(contentWindow, 'resize', resizeWindow);
  23938. dom.bind(contentWindow, 'scroll', scroll);
  23939. const elementLoad = capture(SugarElement.fromDom(editor.getBody()), 'load', resizeDocument);
  23940. editor.on('hide', () => {
  23941. each$1(uiMotherships, m => {
  23942. set$8(m.element, 'display', 'none');
  23943. });
  23944. });
  23945. editor.on('show', () => {
  23946. each$1(uiMotherships, m => {
  23947. remove$6(m.element, 'display');
  23948. });
  23949. });
  23950. editor.on('NodeChange', resizeDocument);
  23951. editor.on('remove', () => {
  23952. elementLoad.unbind();
  23953. dom.unbind(contentWindow, 'resize', resizeWindow);
  23954. dom.unbind(contentWindow, 'scroll', scroll);
  23955. contentWindow = null;
  23956. });
  23957. };
  23958. const attachUiMotherships = (editor, uiRoot, uiRefs) => {
  23959. if (isSplitUiMode(editor)) {
  23960. attachSystemAfter(uiRefs.mainUi.mothership.element, uiRefs.popupUi.mothership);
  23961. }
  23962. attachSystem(uiRoot, uiRefs.dialogUi.mothership);
  23963. };
  23964. const render$1 = (editor, uiRefs, rawUiConfig, backstage, args) => {
  23965. const {mainUi, uiMotherships} = uiRefs;
  23966. const lastToolbarWidth = Cell(0);
  23967. const outerContainer = mainUi.outerContainer;
  23968. iframe(editor);
  23969. const eTargetNode = SugarElement.fromDom(args.targetNode);
  23970. const uiRoot = getContentContainer(getRootNode(eTargetNode));
  23971. attachSystemAfter(eTargetNode, mainUi.mothership);
  23972. attachUiMotherships(editor, uiRoot, uiRefs);
  23973. editor.on('SkinLoaded', () => {
  23974. OuterContainer.setSidebar(outerContainer, rawUiConfig.sidebar, getSidebarShow(editor));
  23975. setToolbar(editor, uiRefs, rawUiConfig, backstage);
  23976. lastToolbarWidth.set(editor.getWin().innerWidth);
  23977. OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
  23978. OuterContainer.setViews(outerContainer, rawUiConfig.views);
  23979. setupEvents$1(editor, uiRefs);
  23980. });
  23981. const socket = OuterContainer.getSocket(outerContainer).getOrDie('Could not find expected socket element');
  23982. if (isiOS12) {
  23983. setAll(socket.element, {
  23984. 'overflow': 'scroll',
  23985. '-webkit-overflow-scrolling': 'touch'
  23986. });
  23987. const limit = first(() => {
  23988. editor.dispatch('ScrollContent');
  23989. }, 20);
  23990. const unbinder = bind(socket.element, 'scroll', limit.throttle);
  23991. editor.on('remove', unbinder.unbind);
  23992. }
  23993. setupReadonlyModeSwitch(editor, uiRefs);
  23994. editor.addCommand('ToggleSidebar', (_ui, value) => {
  23995. OuterContainer.toggleSidebar(outerContainer, value);
  23996. editor.dispatch('ToggleSidebar');
  23997. });
  23998. editor.addQueryValueHandler('ToggleSidebar', () => {
  23999. var _a;
  24000. return (_a = OuterContainer.whichSidebar(outerContainer)) !== null && _a !== void 0 ? _a : '';
  24001. });
  24002. editor.addCommand('ToggleView', (_ui, value) => {
  24003. if (OuterContainer.toggleView(outerContainer, value)) {
  24004. const target = outerContainer.element;
  24005. mainUi.mothership.broadcastOn([dismissPopups()], { target });
  24006. each$1(uiMotherships, m => {
  24007. m.broadcastOn([dismissPopups()], { target });
  24008. });
  24009. if (isNull(OuterContainer.whichView(outerContainer))) {
  24010. editor.focus();
  24011. editor.nodeChanged();
  24012. OuterContainer.refreshToolbar(outerContainer);
  24013. }
  24014. }
  24015. });
  24016. editor.addQueryValueHandler('ToggleView', () => {
  24017. var _a;
  24018. return (_a = OuterContainer.whichView(outerContainer)) !== null && _a !== void 0 ? _a : '';
  24019. });
  24020. const toolbarMode = getToolbarMode(editor);
  24021. const refreshDrawer = () => {
  24022. OuterContainer.refreshToolbar(uiRefs.mainUi.outerContainer);
  24023. };
  24024. if (toolbarMode === ToolbarMode$1.sliding || toolbarMode === ToolbarMode$1.floating) {
  24025. editor.on('ResizeWindow ResizeEditor ResizeContent', () => {
  24026. const width = editor.getWin().innerWidth;
  24027. if (width !== lastToolbarWidth.get()) {
  24028. refreshDrawer();
  24029. lastToolbarWidth.set(width);
  24030. }
  24031. });
  24032. }
  24033. const api = {
  24034. setEnabled: state => {
  24035. broadcastReadonly(uiRefs, !state);
  24036. },
  24037. isEnabled: () => !Disabling.isDisabled(outerContainer)
  24038. };
  24039. return {
  24040. iframeContainer: socket.element.dom,
  24041. editorContainer: outerContainer.element.dom,
  24042. api
  24043. };
  24044. };
  24045. var Iframe = /*#__PURE__*/Object.freeze({
  24046. __proto__: null,
  24047. render: render$1
  24048. });
  24049. const parseToInt = val => {
  24050. const re = /^[0-9\.]+(|px)$/i;
  24051. if (re.test('' + val)) {
  24052. return Optional.some(parseInt('' + val, 10));
  24053. }
  24054. return Optional.none();
  24055. };
  24056. const numToPx = val => isNumber(val) ? val + 'px' : val;
  24057. const calcCappedSize = (size, minSize, maxSize) => {
  24058. const minOverride = minSize.filter(min => size < min);
  24059. const maxOverride = maxSize.filter(max => size > max);
  24060. return minOverride.or(maxOverride).getOr(size);
  24061. };
  24062. const getHeight = editor => {
  24063. const baseHeight = getHeightOption(editor);
  24064. const minHeight = getMinHeightOption(editor);
  24065. const maxHeight = getMaxHeightOption(editor);
  24066. return parseToInt(baseHeight).map(height => calcCappedSize(height, minHeight, maxHeight));
  24067. };
  24068. const getHeightWithFallback = editor => {
  24069. const height = getHeight(editor);
  24070. return height.getOr(getHeightOption(editor));
  24071. };
  24072. const getWidth = editor => {
  24073. const baseWidth = getWidthOption(editor);
  24074. const minWidth = getMinWidthOption(editor);
  24075. const maxWidth = getMaxWidthOption(editor);
  24076. return parseToInt(baseWidth).map(width => calcCappedSize(width, minWidth, maxWidth));
  24077. };
  24078. const getWidthWithFallback = editor => {
  24079. const width = getWidth(editor);
  24080. return width.getOr(getWidthOption(editor));
  24081. };
  24082. const {ToolbarLocation, ToolbarMode} = Options;
  24083. const maximumDistanceToEdge = 40;
  24084. const InlineHeader = (editor, targetElm, uiRefs, backstage, floatContainer) => {
  24085. const {mainUi, uiMotherships} = uiRefs;
  24086. const DOM = global$7.DOM;
  24087. const useFixedToolbarContainer = useFixedContainer(editor);
  24088. const isSticky = isStickyToolbar(editor);
  24089. const editorMaxWidthOpt = getMaxWidthOption(editor).or(getWidth(editor));
  24090. const headerBackstage = backstage.shared.header;
  24091. const isPositionedAtTop = headerBackstage.isPositionedAtTop;
  24092. const toolbarMode = getToolbarMode(editor);
  24093. const isSplitToolbar = toolbarMode === ToolbarMode.sliding || toolbarMode === ToolbarMode.floating;
  24094. const visible = Cell(false);
  24095. const isVisible = () => visible.get() && !editor.removed;
  24096. const calcToolbarOffset = toolbar => isSplitToolbar ? toolbar.fold(constant$1(0), tbar => tbar.components().length > 1 ? get$d(tbar.components()[1].element) : 0) : 0;
  24097. const calcMode = container => {
  24098. switch (getToolbarLocation(editor)) {
  24099. case ToolbarLocation.auto:
  24100. const toolbar = OuterContainer.getToolbar(mainUi.outerContainer);
  24101. const offset = calcToolbarOffset(toolbar);
  24102. const toolbarHeight = get$d(container.element) - offset;
  24103. const targetBounds = box$1(targetElm);
  24104. const roomAtTop = targetBounds.y > toolbarHeight;
  24105. if (roomAtTop) {
  24106. return 'top';
  24107. } else {
  24108. const doc = documentElement(targetElm);
  24109. const docHeight = Math.max(doc.dom.scrollHeight, get$d(doc));
  24110. const roomAtBottom = targetBounds.bottom < docHeight - toolbarHeight;
  24111. if (roomAtBottom) {
  24112. return 'bottom';
  24113. } else {
  24114. const winBounds = win();
  24115. const isRoomAtBottomViewport = winBounds.bottom < targetBounds.bottom - toolbarHeight;
  24116. return isRoomAtBottomViewport ? 'bottom' : 'top';
  24117. }
  24118. }
  24119. case ToolbarLocation.bottom:
  24120. return 'bottom';
  24121. case ToolbarLocation.top:
  24122. default:
  24123. return 'top';
  24124. }
  24125. };
  24126. const setupMode = mode => {
  24127. floatContainer.on(container => {
  24128. Docking.setModes(container, [mode]);
  24129. headerBackstage.setDockingMode(mode);
  24130. const verticalDir = isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop;
  24131. set$9(container.element, Attribute, verticalDir);
  24132. });
  24133. };
  24134. const updateChromeWidth = () => {
  24135. floatContainer.on(container => {
  24136. const maxWidth = editorMaxWidthOpt.getOrThunk(() => {
  24137. const bodyMargin = parseToInt(get$e(body(), 'margin-left')).getOr(0);
  24138. return get$c(body()) - absolute$3(targetElm).left + bodyMargin;
  24139. });
  24140. set$8(container.element, 'max-width', maxWidth + 'px');
  24141. });
  24142. };
  24143. const updateChromePosition = optToolbarWidth => {
  24144. floatContainer.on(container => {
  24145. const toolbar = OuterContainer.getToolbar(mainUi.outerContainer);
  24146. const offset = calcToolbarOffset(toolbar);
  24147. const targetBounds = box$1(targetElm);
  24148. const {top, left} = getOffsetParent$1(editor, mainUi.outerContainer.element).fold(() => {
  24149. return {
  24150. top: isPositionedAtTop() ? Math.max(targetBounds.y - get$d(container.element) + offset, 0) : targetBounds.bottom,
  24151. left: targetBounds.x
  24152. };
  24153. }, offsetParent => {
  24154. var _a;
  24155. const offsetBox = box$1(offsetParent);
  24156. const scrollDelta = (_a = offsetParent.dom.scrollTop) !== null && _a !== void 0 ? _a : 0;
  24157. const isOffsetParentBody = eq(offsetParent, body());
  24158. const topValue = isOffsetParentBody ? Math.max(targetBounds.y - get$d(container.element) + offset, 0) : targetBounds.y - offsetBox.y + scrollDelta - get$d(container.element) + offset;
  24159. return {
  24160. top: isPositionedAtTop() ? topValue : targetBounds.bottom,
  24161. left: isOffsetParentBody ? targetBounds.x : targetBounds.x - offsetBox.x
  24162. };
  24163. });
  24164. const baseProperties = {
  24165. position: 'absolute',
  24166. left: Math.round(left) + 'px',
  24167. top: Math.round(top) + 'px'
  24168. };
  24169. const widthProperties = optToolbarWidth.map(toolbarWidth => {
  24170. const scroll = get$b();
  24171. const minimumToolbarWidth = 150;
  24172. const availableWidth = window.innerWidth - (left - scroll.left);
  24173. const width = Math.max(Math.min(toolbarWidth, availableWidth), minimumToolbarWidth);
  24174. return { width: width + 'px' };
  24175. }).getOr({});
  24176. setAll(mainUi.outerContainer.element, {
  24177. ...baseProperties,
  24178. ...widthProperties
  24179. });
  24180. });
  24181. };
  24182. const getOffsetParent$1 = (editor, element) => isSplitUiMode(editor) ? getOffsetParent(element) : Optional.none();
  24183. const repositionPopups$1 = () => {
  24184. each$1(uiMotherships, m => {
  24185. m.broadcastOn([repositionPopups()], {});
  24186. });
  24187. };
  24188. const restoreAndGetCompleteOuterContainerWidth = () => {
  24189. if (!useFixedToolbarContainer) {
  24190. const toolbarCurrentRightsidePosition = absolute$3(mainUi.outerContainer.element).left + getOuter$1(mainUi.outerContainer.element);
  24191. if (toolbarCurrentRightsidePosition >= window.innerWidth - maximumDistanceToEdge || getRaw(mainUi.outerContainer.element, 'width').isSome()) {
  24192. set$8(mainUi.outerContainer.element, 'position', 'absolute');
  24193. set$8(mainUi.outerContainer.element, 'left', '0px');
  24194. remove$6(mainUi.outerContainer.element, 'width');
  24195. const w = getOuter$1(mainUi.outerContainer.element);
  24196. return Optional.some(w);
  24197. } else {
  24198. return Optional.none();
  24199. }
  24200. } else {
  24201. return Optional.none();
  24202. }
  24203. };
  24204. const update = stickyAction => {
  24205. if (!isVisible()) {
  24206. return;
  24207. }
  24208. if (!useFixedToolbarContainer) {
  24209. updateChromeWidth();
  24210. }
  24211. const optToolbarWidth = useFixedToolbarContainer ? Optional.none() : restoreAndGetCompleteOuterContainerWidth();
  24212. if (isSplitToolbar) {
  24213. OuterContainer.refreshToolbar(mainUi.outerContainer);
  24214. }
  24215. if (!useFixedToolbarContainer) {
  24216. updateChromePosition(optToolbarWidth);
  24217. }
  24218. if (isSticky) {
  24219. floatContainer.on(stickyAction);
  24220. }
  24221. repositionPopups$1();
  24222. };
  24223. const doUpdateMode = () => {
  24224. if (useFixedToolbarContainer || !isSticky || !isVisible()) {
  24225. return false;
  24226. }
  24227. return floatContainer.get().exists(fc => {
  24228. const currentMode = headerBackstage.getDockingMode();
  24229. const newMode = calcMode(fc);
  24230. if (newMode !== currentMode) {
  24231. setupMode(newMode);
  24232. return true;
  24233. } else {
  24234. return false;
  24235. }
  24236. });
  24237. };
  24238. const show = () => {
  24239. visible.set(true);
  24240. set$8(mainUi.outerContainer.element, 'display', 'flex');
  24241. DOM.addClass(editor.getBody(), 'mce-edit-focus');
  24242. each$1(uiMotherships, m => {
  24243. remove$6(m.element, 'display');
  24244. });
  24245. doUpdateMode();
  24246. if (isSplitUiMode(editor)) {
  24247. update(elem => Docking.isDocked(elem) ? Docking.reset(elem) : Docking.refresh(elem));
  24248. } else {
  24249. update(Docking.refresh);
  24250. }
  24251. };
  24252. const hide = () => {
  24253. visible.set(false);
  24254. set$8(mainUi.outerContainer.element, 'display', 'none');
  24255. DOM.removeClass(editor.getBody(), 'mce-edit-focus');
  24256. each$1(uiMotherships, m => {
  24257. set$8(m.element, 'display', 'none');
  24258. });
  24259. };
  24260. const updateMode = () => {
  24261. const changedMode = doUpdateMode();
  24262. if (changedMode) {
  24263. update(Docking.reset);
  24264. }
  24265. };
  24266. return {
  24267. isVisible,
  24268. isPositionedAtTop,
  24269. show,
  24270. hide,
  24271. update,
  24272. updateMode,
  24273. repositionPopups: repositionPopups$1
  24274. };
  24275. };
  24276. const getTargetPosAndBounds = (targetElm, isToolbarTop) => {
  24277. const bounds = box$1(targetElm);
  24278. return {
  24279. pos: isToolbarTop ? bounds.y : bounds.bottom,
  24280. bounds
  24281. };
  24282. };
  24283. const setupEvents = (editor, targetElm, ui, toolbarPersist) => {
  24284. const prevPosAndBounds = Cell(getTargetPosAndBounds(targetElm, ui.isPositionedAtTop()));
  24285. const resizeContent = e => {
  24286. const {pos, bounds} = getTargetPosAndBounds(targetElm, ui.isPositionedAtTop());
  24287. const {
  24288. pos: prevPos,
  24289. bounds: prevBounds
  24290. } = prevPosAndBounds.get();
  24291. const hasResized = bounds.height !== prevBounds.height || bounds.width !== prevBounds.width;
  24292. prevPosAndBounds.set({
  24293. pos,
  24294. bounds
  24295. });
  24296. if (hasResized) {
  24297. fireResizeContent(editor, e);
  24298. }
  24299. if (ui.isVisible()) {
  24300. if (prevPos !== pos) {
  24301. ui.update(Docking.reset);
  24302. } else if (hasResized) {
  24303. ui.updateMode();
  24304. ui.repositionPopups();
  24305. }
  24306. }
  24307. };
  24308. if (!toolbarPersist) {
  24309. editor.on('activate', ui.show);
  24310. editor.on('deactivate', ui.hide);
  24311. }
  24312. editor.on('SkinLoaded ResizeWindow', () => ui.update(Docking.reset));
  24313. editor.on('NodeChange keydown', e => {
  24314. requestAnimationFrame(() => resizeContent(e));
  24315. });
  24316. let lastScrollX = 0;
  24317. const updateUi = last(() => ui.update(Docking.refresh), 33);
  24318. editor.on('ScrollWindow', () => {
  24319. const newScrollX = get$b().left;
  24320. if (newScrollX !== lastScrollX) {
  24321. lastScrollX = newScrollX;
  24322. updateUi.throttle();
  24323. }
  24324. ui.updateMode();
  24325. });
  24326. if (isSplitUiMode(editor)) {
  24327. editor.on('ElementScroll', _args => {
  24328. ui.update(Docking.refresh);
  24329. });
  24330. }
  24331. const elementLoad = unbindable();
  24332. elementLoad.set(capture(SugarElement.fromDom(editor.getBody()), 'load', e => resizeContent(e.raw)));
  24333. editor.on('remove', () => {
  24334. elementLoad.clear();
  24335. });
  24336. };
  24337. const render = (editor, uiRefs, rawUiConfig, backstage, args) => {
  24338. const {mainUi} = uiRefs;
  24339. const floatContainer = value$2();
  24340. const targetElm = SugarElement.fromDom(args.targetNode);
  24341. const ui = InlineHeader(editor, targetElm, uiRefs, backstage, floatContainer);
  24342. const toolbarPersist = isToolbarPersist(editor);
  24343. inline(editor);
  24344. const render = () => {
  24345. if (floatContainer.isSet()) {
  24346. ui.show();
  24347. return;
  24348. }
  24349. floatContainer.set(OuterContainer.getHeader(mainUi.outerContainer).getOrDie());
  24350. const uiContainer = getUiContainer(editor);
  24351. if (isSplitUiMode(editor)) {
  24352. attachSystemAfter(targetElm, mainUi.mothership);
  24353. attachSystemAfter(targetElm, uiRefs.popupUi.mothership);
  24354. } else {
  24355. attachSystem(uiContainer, mainUi.mothership);
  24356. }
  24357. attachSystem(uiContainer, uiRefs.dialogUi.mothership);
  24358. setToolbar(editor, uiRefs, rawUiConfig, backstage);
  24359. OuterContainer.setMenubar(mainUi.outerContainer, identifyMenus(editor, rawUiConfig));
  24360. ui.show();
  24361. setupEvents(editor, targetElm, ui, toolbarPersist);
  24362. editor.nodeChanged();
  24363. };
  24364. editor.on('show', render);
  24365. editor.on('hide', ui.hide);
  24366. if (!toolbarPersist) {
  24367. editor.on('focus', render);
  24368. editor.on('blur', ui.hide);
  24369. }
  24370. editor.on('init', () => {
  24371. if (editor.hasFocus() || toolbarPersist) {
  24372. render();
  24373. }
  24374. });
  24375. setupReadonlyModeSwitch(editor, uiRefs);
  24376. const api = {
  24377. show: render,
  24378. hide: ui.hide,
  24379. setEnabled: state => {
  24380. broadcastReadonly(uiRefs, !state);
  24381. },
  24382. isEnabled: () => !Disabling.isDisabled(mainUi.outerContainer)
  24383. };
  24384. return {
  24385. editorContainer: mainUi.outerContainer.element.dom,
  24386. api
  24387. };
  24388. };
  24389. var Inline = /*#__PURE__*/Object.freeze({
  24390. __proto__: null,
  24391. render: render
  24392. });
  24393. const LazyUiReferences = () => {
  24394. const dialogUi = value$2();
  24395. const popupUi = value$2();
  24396. const mainUi = value$2();
  24397. const lazyGetInOuterOrDie = (label, f) => () => mainUi.get().bind(oc => f(oc.outerContainer)).getOrDie(`Could not find ${ label } element in OuterContainer`);
  24398. const getUiMotherships = () => {
  24399. const optDialogMothership = dialogUi.get().map(ui => ui.mothership);
  24400. const optPopupMothership = popupUi.get().map(ui => ui.mothership);
  24401. return optDialogMothership.fold(() => optPopupMothership.toArray(), dm => optPopupMothership.fold(() => [dm], pm => eq(dm.element, pm.element) ? [dm] : [
  24402. dm,
  24403. pm
  24404. ]));
  24405. };
  24406. return {
  24407. dialogUi,
  24408. popupUi,
  24409. mainUi,
  24410. getUiMotherships,
  24411. lazyGetInOuterOrDie
  24412. };
  24413. };
  24414. const showContextToolbarEvent = 'contexttoolbar-show';
  24415. const hideContextToolbarEvent = 'contexttoolbar-hide';
  24416. const getFormApi = input => ({
  24417. hide: () => emit(input, sandboxClose()),
  24418. getValue: () => Representing.getValue(input)
  24419. });
  24420. const runOnExecute = (memInput, original) => run$1(internalToolbarButtonExecute, (comp, se) => {
  24421. const input = memInput.get(comp);
  24422. const formApi = getFormApi(input);
  24423. original.onAction(formApi, se.event.buttonApi);
  24424. });
  24425. const renderContextButton = (memInput, button, providers) => {
  24426. const {primary, ...rest} = button.original;
  24427. const bridged = getOrDie(createToolbarButton({
  24428. ...rest,
  24429. type: 'button',
  24430. onAction: noop
  24431. }));
  24432. return renderToolbarButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
  24433. };
  24434. const renderContextToggleButton = (memInput, button, providers) => {
  24435. const {primary, ...rest} = button.original;
  24436. const bridged = getOrDie(createToggleButton({
  24437. ...rest,
  24438. type: 'togglebutton',
  24439. onAction: noop
  24440. }));
  24441. return renderToolbarToggleButtonWith(bridged, providers, [runOnExecute(memInput, button)]);
  24442. };
  24443. const isToggleButton = button => button.type === 'contextformtogglebutton';
  24444. const generateOne = (memInput, button, providersBackstage) => {
  24445. if (isToggleButton(button)) {
  24446. return renderContextToggleButton(memInput, button, providersBackstage);
  24447. } else {
  24448. return renderContextButton(memInput, button, providersBackstage);
  24449. }
  24450. };
  24451. const generate = (memInput, buttons, providersBackstage) => {
  24452. const mementos = map$2(buttons, button => record(generateOne(memInput, button, providersBackstage)));
  24453. const asSpecs = () => map$2(mementos, mem => mem.asSpec());
  24454. const findPrimary = compInSystem => findMap(buttons, (button, i) => {
  24455. if (button.primary) {
  24456. return Optional.from(mementos[i]).bind(mem => mem.getOpt(compInSystem)).filter(not(Disabling.isDisabled));
  24457. } else {
  24458. return Optional.none();
  24459. }
  24460. });
  24461. return {
  24462. asSpecs,
  24463. findPrimary
  24464. };
  24465. };
  24466. const buildInitGroups = (ctx, providers) => {
  24467. const inputAttributes = ctx.label.fold(() => ({}), label => ({ 'aria-label': label }));
  24468. const memInput = record(Input.sketch({
  24469. inputClasses: [
  24470. 'tox-toolbar-textfield',
  24471. 'tox-toolbar-nav-js'
  24472. ],
  24473. data: ctx.initValue(),
  24474. inputAttributes,
  24475. selectOnFocus: true,
  24476. inputBehaviours: derive$1([Keying.config({
  24477. mode: 'special',
  24478. onEnter: input => commands.findPrimary(input).map(primary => {
  24479. emitExecute(primary);
  24480. return true;
  24481. }),
  24482. onLeft: (comp, se) => {
  24483. se.cut();
  24484. return Optional.none();
  24485. },
  24486. onRight: (comp, se) => {
  24487. se.cut();
  24488. return Optional.none();
  24489. }
  24490. })])
  24491. }));
  24492. const commands = generate(memInput, ctx.commands, providers);
  24493. return [
  24494. {
  24495. title: Optional.none(),
  24496. items: [memInput.asSpec()]
  24497. },
  24498. {
  24499. title: Optional.none(),
  24500. items: commands.asSpecs()
  24501. }
  24502. ];
  24503. };
  24504. const renderContextForm = (toolbarType, ctx, providers) => renderToolbar({
  24505. type: toolbarType,
  24506. uid: generate$6('context-toolbar'),
  24507. initGroups: buildInitGroups(ctx, providers),
  24508. onEscape: Optional.none,
  24509. cyclicKeying: true,
  24510. providers
  24511. });
  24512. const ContextForm = {
  24513. renderContextForm,
  24514. buildInitGroups
  24515. };
  24516. const isVerticalOverlap = (a, b, threshold) => b.bottom - a.y >= threshold && a.bottom - b.y >= threshold;
  24517. const getRangeRect = rng => {
  24518. const rect = rng.getBoundingClientRect();
  24519. if (rect.height <= 0 && rect.width <= 0) {
  24520. const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset).element;
  24521. const elm = isText(leaf$1) ? parent(leaf$1) : Optional.some(leaf$1);
  24522. return elm.filter(isElement$1).map(e => e.dom.getBoundingClientRect()).getOr(rect);
  24523. } else {
  24524. return rect;
  24525. }
  24526. };
  24527. const getSelectionBounds = editor => {
  24528. const rng = editor.selection.getRng();
  24529. const rect = getRangeRect(rng);
  24530. if (editor.inline) {
  24531. const scroll = get$b();
  24532. return bounds(scroll.left + rect.left, scroll.top + rect.top, rect.width, rect.height);
  24533. } else {
  24534. const bodyPos = absolute$2(SugarElement.fromDom(editor.getBody()));
  24535. return bounds(bodyPos.x + rect.left, bodyPos.y + rect.top, rect.width, rect.height);
  24536. }
  24537. };
  24538. const getAnchorElementBounds = (editor, lastElement) => lastElement.filter(elem => inBody(elem) && isHTMLElement(elem)).map(absolute$2).getOrThunk(() => getSelectionBounds(editor));
  24539. const getHorizontalBounds = (contentAreaBox, viewportBounds, margin) => {
  24540. const x = Math.max(contentAreaBox.x + margin, viewportBounds.x);
  24541. const right = Math.min(contentAreaBox.right - margin, viewportBounds.right);
  24542. return {
  24543. x,
  24544. width: right - x
  24545. };
  24546. };
  24547. const getVerticalBounds = (editor, contentAreaBox, viewportBounds, isToolbarLocationTop, toolbarType, margin) => {
  24548. const container = SugarElement.fromDom(editor.getContainer());
  24549. const header = descendant(container, '.tox-editor-header').getOr(container);
  24550. const headerBox = box$1(header);
  24551. const isToolbarBelowContentArea = headerBox.y >= contentAreaBox.bottom;
  24552. const isToolbarAbove = isToolbarLocationTop && !isToolbarBelowContentArea;
  24553. if (editor.inline && isToolbarAbove) {
  24554. return {
  24555. y: Math.max(headerBox.bottom + margin, viewportBounds.y),
  24556. bottom: viewportBounds.bottom
  24557. };
  24558. }
  24559. if (editor.inline && !isToolbarAbove) {
  24560. return {
  24561. y: viewportBounds.y,
  24562. bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
  24563. };
  24564. }
  24565. const containerBounds = toolbarType === 'line' ? box$1(container) : contentAreaBox;
  24566. if (isToolbarAbove) {
  24567. return {
  24568. y: Math.max(headerBox.bottom + margin, viewportBounds.y),
  24569. bottom: Math.min(containerBounds.bottom - margin, viewportBounds.bottom)
  24570. };
  24571. }
  24572. return {
  24573. y: Math.max(containerBounds.y + margin, viewportBounds.y),
  24574. bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
  24575. };
  24576. };
  24577. const getContextToolbarBounds = (editor, sharedBackstage, toolbarType, margin = 0) => {
  24578. const viewportBounds = getBounds$3(window);
  24579. const contentAreaBox = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
  24580. const toolbarOrMenubarEnabled = isMenubarEnabled(editor) || isToolbarEnabled(editor) || isMultipleToolbars(editor);
  24581. const {x, width} = getHorizontalBounds(contentAreaBox, viewportBounds, margin);
  24582. if (editor.inline && !toolbarOrMenubarEnabled) {
  24583. return bounds(x, viewportBounds.y, width, viewportBounds.height);
  24584. } else {
  24585. const isToolbarTop = sharedBackstage.header.isPositionedAtTop();
  24586. const {y, bottom} = getVerticalBounds(editor, contentAreaBox, viewportBounds, isToolbarTop, toolbarType, margin);
  24587. return bounds(x, y, width, bottom - y);
  24588. }
  24589. };
  24590. const bubbleSize$1 = 12;
  24591. const bubbleAlignments$1 = {
  24592. valignCentre: [],
  24593. alignCentre: [],
  24594. alignLeft: ['tox-pop--align-left'],
  24595. alignRight: ['tox-pop--align-right'],
  24596. right: ['tox-pop--right'],
  24597. left: ['tox-pop--left'],
  24598. bottom: ['tox-pop--bottom'],
  24599. top: ['tox-pop--top'],
  24600. inset: ['tox-pop--inset']
  24601. };
  24602. const anchorOverrides = {
  24603. maxHeightFunction: expandable$1(),
  24604. maxWidthFunction: expandable()
  24605. };
  24606. const isEntireElementSelected = (editor, elem) => {
  24607. const rng = editor.selection.getRng();
  24608. const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset);
  24609. return rng.startContainer === rng.endContainer && rng.startOffset === rng.endOffset - 1 && eq(leaf$1.element, elem);
  24610. };
  24611. const preservePosition = (elem, position, f) => {
  24612. const currentPosition = getRaw(elem, 'position');
  24613. set$8(elem, 'position', position);
  24614. const result = f(elem);
  24615. currentPosition.each(pos => set$8(elem, 'position', pos));
  24616. return result;
  24617. };
  24618. const shouldUseInsetLayouts = position => position === 'node';
  24619. const determineInsetLayout = (editor, contextbar, elem, data, bounds) => {
  24620. const selectionBounds = getSelectionBounds(editor);
  24621. const isSameAnchorElement = data.lastElement().exists(prev => eq(elem, prev));
  24622. if (isEntireElementSelected(editor, elem)) {
  24623. return isSameAnchorElement ? preserve : north;
  24624. } else if (isSameAnchorElement) {
  24625. return preservePosition(contextbar, data.getMode(), () => {
  24626. const isOverlapping = isVerticalOverlap(selectionBounds, box$1(contextbar), -20);
  24627. return isOverlapping && !data.isReposition() ? flip : preserve;
  24628. });
  24629. } else {
  24630. const yBounds = data.getMode() === 'fixed' ? bounds.y + get$b().top : bounds.y;
  24631. const contextbarHeight = get$d(contextbar) + bubbleSize$1;
  24632. return yBounds + contextbarHeight <= selectionBounds.y ? north : south;
  24633. }
  24634. };
  24635. const getAnchorSpec$2 = (editor, mobile, data, position) => {
  24636. const smartInsetLayout = elem => (anchor, element, bubbles, placee, bounds) => {
  24637. const layout = determineInsetLayout(editor, placee, elem, data, bounds);
  24638. const newAnchor = {
  24639. ...anchor,
  24640. y: bounds.y,
  24641. height: bounds.height
  24642. };
  24643. return {
  24644. ...layout(newAnchor, element, bubbles, placee, bounds),
  24645. alwaysFit: true
  24646. };
  24647. };
  24648. const getInsetLayouts = elem => shouldUseInsetLayouts(position) ? [smartInsetLayout(elem)] : [];
  24649. const desktopAnchorSpecLayouts = {
  24650. onLtr: elem => [
  24651. north$2,
  24652. south$2,
  24653. northeast$2,
  24654. southeast$2,
  24655. northwest$2,
  24656. southwest$2
  24657. ].concat(getInsetLayouts(elem)),
  24658. onRtl: elem => [
  24659. north$2,
  24660. south$2,
  24661. northwest$2,
  24662. southwest$2,
  24663. northeast$2,
  24664. southeast$2
  24665. ].concat(getInsetLayouts(elem))
  24666. };
  24667. const mobileAnchorSpecLayouts = {
  24668. onLtr: elem => [
  24669. south$2,
  24670. southeast$2,
  24671. southwest$2,
  24672. northeast$2,
  24673. northwest$2,
  24674. north$2
  24675. ].concat(getInsetLayouts(elem)),
  24676. onRtl: elem => [
  24677. south$2,
  24678. southwest$2,
  24679. southeast$2,
  24680. northwest$2,
  24681. northeast$2,
  24682. north$2
  24683. ].concat(getInsetLayouts(elem))
  24684. };
  24685. return mobile ? mobileAnchorSpecLayouts : desktopAnchorSpecLayouts;
  24686. };
  24687. const getAnchorLayout = (editor, position, isTouch, data) => {
  24688. if (position === 'line') {
  24689. return {
  24690. bubble: nu$5(bubbleSize$1, 0, bubbleAlignments$1),
  24691. layouts: {
  24692. onLtr: () => [east$2],
  24693. onRtl: () => [west$2]
  24694. },
  24695. overrides: anchorOverrides
  24696. };
  24697. } else {
  24698. return {
  24699. bubble: nu$5(0, bubbleSize$1, bubbleAlignments$1, 1 / bubbleSize$1),
  24700. layouts: getAnchorSpec$2(editor, isTouch, data, position),
  24701. overrides: anchorOverrides
  24702. };
  24703. }
  24704. };
  24705. const matchTargetWith = (elem, candidates) => {
  24706. const ctxs = filter$2(candidates, toolbarApi => toolbarApi.predicate(elem.dom));
  24707. const {pass, fail} = partition$3(ctxs, t => t.type === 'contexttoolbar');
  24708. return {
  24709. contextToolbars: pass,
  24710. contextForms: fail
  24711. };
  24712. };
  24713. const filterByPositionForStartNode = toolbars => {
  24714. if (toolbars.length <= 1) {
  24715. return toolbars;
  24716. } else {
  24717. const doesPositionExist = value => exists(toolbars, t => t.position === value);
  24718. const filterToolbarsByPosition = value => filter$2(toolbars, t => t.position === value);
  24719. const hasSelectionToolbars = doesPositionExist('selection');
  24720. const hasNodeToolbars = doesPositionExist('node');
  24721. if (hasSelectionToolbars || hasNodeToolbars) {
  24722. if (hasNodeToolbars && hasSelectionToolbars) {
  24723. const nodeToolbars = filterToolbarsByPosition('node');
  24724. const selectionToolbars = map$2(filterToolbarsByPosition('selection'), t => ({
  24725. ...t,
  24726. position: 'node'
  24727. }));
  24728. return nodeToolbars.concat(selectionToolbars);
  24729. } else {
  24730. return hasSelectionToolbars ? filterToolbarsByPosition('selection') : filterToolbarsByPosition('node');
  24731. }
  24732. } else {
  24733. return filterToolbarsByPosition('line');
  24734. }
  24735. }
  24736. };
  24737. const filterByPositionForAncestorNode = toolbars => {
  24738. if (toolbars.length <= 1) {
  24739. return toolbars;
  24740. } else {
  24741. const findPosition = value => find$5(toolbars, t => t.position === value);
  24742. const basePosition = findPosition('selection').orThunk(() => findPosition('node')).orThunk(() => findPosition('line')).map(t => t.position);
  24743. return basePosition.fold(() => [], pos => filter$2(toolbars, t => t.position === pos));
  24744. }
  24745. };
  24746. const matchStartNode = (elem, nodeCandidates, editorCandidates) => {
  24747. const nodeMatches = matchTargetWith(elem, nodeCandidates);
  24748. if (nodeMatches.contextForms.length > 0) {
  24749. return Optional.some({
  24750. elem,
  24751. toolbars: [nodeMatches.contextForms[0]]
  24752. });
  24753. } else {
  24754. const editorMatches = matchTargetWith(elem, editorCandidates);
  24755. if (editorMatches.contextForms.length > 0) {
  24756. return Optional.some({
  24757. elem,
  24758. toolbars: [editorMatches.contextForms[0]]
  24759. });
  24760. } else if (nodeMatches.contextToolbars.length > 0 || editorMatches.contextToolbars.length > 0) {
  24761. const toolbars = filterByPositionForStartNode(nodeMatches.contextToolbars.concat(editorMatches.contextToolbars));
  24762. return Optional.some({
  24763. elem,
  24764. toolbars
  24765. });
  24766. } else {
  24767. return Optional.none();
  24768. }
  24769. }
  24770. };
  24771. const matchAncestor = (isRoot, startNode, scopes) => {
  24772. if (isRoot(startNode)) {
  24773. return Optional.none();
  24774. } else {
  24775. return ancestor$2(startNode, ancestorElem => {
  24776. if (isElement$1(ancestorElem)) {
  24777. const {contextToolbars, contextForms} = matchTargetWith(ancestorElem, scopes.inNodeScope);
  24778. const toolbars = contextForms.length > 0 ? contextForms : filterByPositionForAncestorNode(contextToolbars);
  24779. return toolbars.length > 0 ? Optional.some({
  24780. elem: ancestorElem,
  24781. toolbars
  24782. }) : Optional.none();
  24783. } else {
  24784. return Optional.none();
  24785. }
  24786. }, isRoot);
  24787. }
  24788. };
  24789. const lookup$1 = (scopes, editor) => {
  24790. const rootElem = SugarElement.fromDom(editor.getBody());
  24791. const isRoot = elem => eq(elem, rootElem);
  24792. const isOutsideRoot = startNode => !isRoot(startNode) && !contains(rootElem, startNode);
  24793. const startNode = SugarElement.fromDom(editor.selection.getNode());
  24794. if (isOutsideRoot(startNode)) {
  24795. return Optional.none();
  24796. }
  24797. return matchStartNode(startNode, scopes.inNodeScope, scopes.inEditorScope).orThunk(() => matchAncestor(isRoot, startNode, scopes));
  24798. };
  24799. const categorise = (contextToolbars, navigate) => {
  24800. const forms = {};
  24801. const inNodeScope = [];
  24802. const inEditorScope = [];
  24803. const formNavigators = {};
  24804. const lookupTable = {};
  24805. const registerForm = (key, toolbarSpec) => {
  24806. const contextForm = getOrDie(createContextForm(toolbarSpec));
  24807. forms[key] = contextForm;
  24808. contextForm.launch.map(launch => {
  24809. formNavigators['form:' + key + ''] = {
  24810. ...toolbarSpec.launch,
  24811. type: launch.type === 'contextformtogglebutton' ? 'togglebutton' : 'button',
  24812. onAction: () => {
  24813. navigate(contextForm);
  24814. }
  24815. };
  24816. });
  24817. if (contextForm.scope === 'editor') {
  24818. inEditorScope.push(contextForm);
  24819. } else {
  24820. inNodeScope.push(contextForm);
  24821. }
  24822. lookupTable[key] = contextForm;
  24823. };
  24824. const registerToolbar = (key, toolbarSpec) => {
  24825. createContextToolbar(toolbarSpec).each(contextToolbar => {
  24826. if (toolbarSpec.scope === 'editor') {
  24827. inEditorScope.push(contextToolbar);
  24828. } else {
  24829. inNodeScope.push(contextToolbar);
  24830. }
  24831. lookupTable[key] = contextToolbar;
  24832. });
  24833. };
  24834. const keys$1 = keys(contextToolbars);
  24835. each$1(keys$1, key => {
  24836. const toolbarApi = contextToolbars[key];
  24837. if (toolbarApi.type === 'contextform') {
  24838. registerForm(key, toolbarApi);
  24839. } else if (toolbarApi.type === 'contexttoolbar') {
  24840. registerToolbar(key, toolbarApi);
  24841. }
  24842. });
  24843. return {
  24844. forms,
  24845. inNodeScope,
  24846. inEditorScope,
  24847. lookupTable,
  24848. formNavigators
  24849. };
  24850. };
  24851. const forwardSlideEvent = generate$6('forward-slide');
  24852. const backSlideEvent = generate$6('backward-slide');
  24853. const changeSlideEvent = generate$6('change-slide-event');
  24854. const resizingClass = 'tox-pop--resizing';
  24855. const renderContextToolbar = spec => {
  24856. const stack = Cell([]);
  24857. return InlineView.sketch({
  24858. dom: {
  24859. tag: 'div',
  24860. classes: ['tox-pop']
  24861. },
  24862. fireDismissalEventInstead: { event: 'doNotDismissYet' },
  24863. onShow: comp => {
  24864. stack.set([]);
  24865. InlineView.getContent(comp).each(c => {
  24866. remove$6(c.element, 'visibility');
  24867. });
  24868. remove$2(comp.element, resizingClass);
  24869. remove$6(comp.element, 'width');
  24870. },
  24871. inlineBehaviours: derive$1([
  24872. config('context-toolbar-events', [
  24873. runOnSource(transitionend(), (comp, se) => {
  24874. if (se.event.raw.propertyName === 'width') {
  24875. remove$2(comp.element, resizingClass);
  24876. remove$6(comp.element, 'width');
  24877. }
  24878. }),
  24879. run$1(changeSlideEvent, (comp, se) => {
  24880. const elem = comp.element;
  24881. remove$6(elem, 'width');
  24882. const currentWidth = get$c(elem);
  24883. InlineView.setContent(comp, se.event.contents);
  24884. add$2(elem, resizingClass);
  24885. const newWidth = get$c(elem);
  24886. set$8(elem, 'width', currentWidth + 'px');
  24887. InlineView.getContent(comp).each(newContents => {
  24888. se.event.focus.bind(f => {
  24889. focus$3(f);
  24890. return search(elem);
  24891. }).orThunk(() => {
  24892. Keying.focusIn(newContents);
  24893. return active$1(getRootNode(elem));
  24894. });
  24895. });
  24896. setTimeout(() => {
  24897. set$8(comp.element, 'width', newWidth + 'px');
  24898. }, 0);
  24899. }),
  24900. run$1(forwardSlideEvent, (comp, se) => {
  24901. InlineView.getContent(comp).each(oldContents => {
  24902. stack.set(stack.get().concat([{
  24903. bar: oldContents,
  24904. focus: active$1(getRootNode(comp.element))
  24905. }]));
  24906. });
  24907. emitWith(comp, changeSlideEvent, {
  24908. contents: se.event.forwardContents,
  24909. focus: Optional.none()
  24910. });
  24911. }),
  24912. run$1(backSlideEvent, (comp, _se) => {
  24913. last$1(stack.get()).each(last => {
  24914. stack.set(stack.get().slice(0, stack.get().length - 1));
  24915. emitWith(comp, changeSlideEvent, {
  24916. contents: premade(last.bar),
  24917. focus: last.focus
  24918. });
  24919. });
  24920. })
  24921. ]),
  24922. Keying.config({
  24923. mode: 'special',
  24924. onEscape: comp => last$1(stack.get()).fold(() => spec.onEscape(), _ => {
  24925. emit(comp, backSlideEvent);
  24926. return Optional.some(true);
  24927. })
  24928. })
  24929. ]),
  24930. lazySink: () => Result.value(spec.sink)
  24931. });
  24932. };
  24933. const transitionClass = 'tox-pop--transition';
  24934. const register$9 = (editor, registryContextToolbars, sink, extras) => {
  24935. const backstage = extras.backstage;
  24936. const sharedBackstage = backstage.shared;
  24937. const isTouch = detect$2().deviceType.isTouch;
  24938. const lastElement = value$2();
  24939. const lastTrigger = value$2();
  24940. const lastContextPosition = value$2();
  24941. const contextbar = build$1(renderContextToolbar({
  24942. sink,
  24943. onEscape: () => {
  24944. editor.focus();
  24945. return Optional.some(true);
  24946. }
  24947. }));
  24948. const getBounds = () => {
  24949. const position = lastContextPosition.get().getOr('node');
  24950. const margin = shouldUseInsetLayouts(position) ? 1 : 0;
  24951. return getContextToolbarBounds(editor, sharedBackstage, position, margin);
  24952. };
  24953. const canLaunchToolbar = () => {
  24954. return !editor.removed && !(isTouch() && backstage.isContextMenuOpen());
  24955. };
  24956. const isSameLaunchElement = elem => is$1(lift2(elem, lastElement.get(), eq), true);
  24957. const shouldContextToolbarHide = () => {
  24958. if (!canLaunchToolbar()) {
  24959. return true;
  24960. } else {
  24961. const contextToolbarBounds = getBounds();
  24962. const anchorBounds = is$1(lastContextPosition.get(), 'node') ? getAnchorElementBounds(editor, lastElement.get()) : getSelectionBounds(editor);
  24963. return contextToolbarBounds.height <= 0 || !isVerticalOverlap(anchorBounds, contextToolbarBounds, 0.01);
  24964. }
  24965. };
  24966. const close = () => {
  24967. lastElement.clear();
  24968. lastTrigger.clear();
  24969. lastContextPosition.clear();
  24970. InlineView.hide(contextbar);
  24971. };
  24972. const hideOrRepositionIfNecessary = () => {
  24973. if (InlineView.isOpen(contextbar)) {
  24974. const contextBarEle = contextbar.element;
  24975. remove$6(contextBarEle, 'display');
  24976. if (shouldContextToolbarHide()) {
  24977. set$8(contextBarEle, 'display', 'none');
  24978. } else {
  24979. lastTrigger.set(0);
  24980. InlineView.reposition(contextbar);
  24981. }
  24982. }
  24983. };
  24984. const wrapInPopDialog = toolbarSpec => ({
  24985. dom: {
  24986. tag: 'div',
  24987. classes: ['tox-pop__dialog']
  24988. },
  24989. components: [toolbarSpec],
  24990. behaviours: derive$1([
  24991. Keying.config({ mode: 'acyclic' }),
  24992. config('pop-dialog-wrap-events', [
  24993. runOnAttached(comp => {
  24994. editor.shortcuts.add('ctrl+F9', 'focus statusbar', () => Keying.focusIn(comp));
  24995. }),
  24996. runOnDetached(_comp => {
  24997. editor.shortcuts.remove('ctrl+F9');
  24998. })
  24999. ])
  25000. ])
  25001. });
  25002. const getScopes = cached(() => categorise(registryContextToolbars, toolbarApi => {
  25003. const alloySpec = buildToolbar([toolbarApi]);
  25004. emitWith(contextbar, forwardSlideEvent, { forwardContents: wrapInPopDialog(alloySpec) });
  25005. }));
  25006. const buildContextToolbarGroups = (allButtons, ctx) => identifyButtons(editor, {
  25007. buttons: allButtons,
  25008. toolbar: ctx.items,
  25009. allowToolbarGroups: false
  25010. }, extras.backstage, Optional.some(['form:']));
  25011. const buildContextFormGroups = (ctx, providers) => ContextForm.buildInitGroups(ctx, providers);
  25012. const buildToolbar = toolbars => {
  25013. const {buttons} = editor.ui.registry.getAll();
  25014. const scopes = getScopes();
  25015. const allButtons = {
  25016. ...buttons,
  25017. ...scopes.formNavigators
  25018. };
  25019. const toolbarType = getToolbarMode(editor) === ToolbarMode$1.scrolling ? ToolbarMode$1.scrolling : ToolbarMode$1.default;
  25020. const initGroups = flatten(map$2(toolbars, ctx => ctx.type === 'contexttoolbar' ? buildContextToolbarGroups(allButtons, ctx) : buildContextFormGroups(ctx, sharedBackstage.providers)));
  25021. return renderToolbar({
  25022. type: toolbarType,
  25023. uid: generate$6('context-toolbar'),
  25024. initGroups,
  25025. onEscape: Optional.none,
  25026. cyclicKeying: true,
  25027. providers: sharedBackstage.providers
  25028. });
  25029. };
  25030. const getAnchor = (position, element) => {
  25031. const anchorage = position === 'node' ? sharedBackstage.anchors.node(element) : sharedBackstage.anchors.cursor();
  25032. const anchorLayout = getAnchorLayout(editor, position, isTouch(), {
  25033. lastElement: lastElement.get,
  25034. isReposition: () => is$1(lastTrigger.get(), 0),
  25035. getMode: () => Positioning.getMode(sink)
  25036. });
  25037. return deepMerge(anchorage, anchorLayout);
  25038. };
  25039. const launchContext = (toolbarApi, elem) => {
  25040. launchContextToolbar.cancel();
  25041. if (!canLaunchToolbar()) {
  25042. return;
  25043. }
  25044. const toolbarSpec = buildToolbar(toolbarApi);
  25045. const position = toolbarApi[0].position;
  25046. const anchor = getAnchor(position, elem);
  25047. lastContextPosition.set(position);
  25048. lastTrigger.set(1);
  25049. const contextBarEle = contextbar.element;
  25050. remove$6(contextBarEle, 'display');
  25051. if (!isSameLaunchElement(elem)) {
  25052. remove$2(contextBarEle, transitionClass);
  25053. Positioning.reset(sink, contextbar);
  25054. }
  25055. InlineView.showWithinBounds(contextbar, wrapInPopDialog(toolbarSpec), {
  25056. anchor,
  25057. transition: {
  25058. classes: [transitionClass],
  25059. mode: 'placement'
  25060. }
  25061. }, () => Optional.some(getBounds()));
  25062. elem.fold(lastElement.clear, lastElement.set);
  25063. if (shouldContextToolbarHide()) {
  25064. set$8(contextBarEle, 'display', 'none');
  25065. }
  25066. };
  25067. let isDragging = false;
  25068. const launchContextToolbar = last(() => {
  25069. if (!editor.hasFocus() || editor.removed || isDragging) {
  25070. return;
  25071. }
  25072. if (has(contextbar.element, transitionClass)) {
  25073. launchContextToolbar.throttle();
  25074. } else {
  25075. const scopes = getScopes();
  25076. lookup$1(scopes, editor).fold(close, info => {
  25077. launchContext(info.toolbars, Optional.some(info.elem));
  25078. });
  25079. }
  25080. }, 17);
  25081. editor.on('init', () => {
  25082. editor.on('remove', close);
  25083. editor.on('ScrollContent ScrollWindow ObjectResized ResizeEditor longpress', hideOrRepositionIfNecessary);
  25084. editor.on('click keyup focus SetContent', launchContextToolbar.throttle);
  25085. editor.on(hideContextToolbarEvent, close);
  25086. editor.on(showContextToolbarEvent, e => {
  25087. const scopes = getScopes();
  25088. get$g(scopes.lookupTable, e.toolbarKey).each(ctx => {
  25089. launchContext([ctx], someIf(e.target !== editor, e.target));
  25090. InlineView.getContent(contextbar).each(Keying.focusIn);
  25091. });
  25092. });
  25093. editor.on('focusout', _e => {
  25094. global$9.setEditorTimeout(editor, () => {
  25095. if (search(sink.element).isNone() && search(contextbar.element).isNone()) {
  25096. close();
  25097. }
  25098. }, 0);
  25099. });
  25100. editor.on('SwitchMode', () => {
  25101. if (editor.mode.isReadOnly()) {
  25102. close();
  25103. }
  25104. });
  25105. editor.on('AfterProgressState', event => {
  25106. if (event.state) {
  25107. close();
  25108. } else if (editor.hasFocus()) {
  25109. launchContextToolbar.throttle();
  25110. }
  25111. });
  25112. editor.on('dragstart', () => {
  25113. isDragging = true;
  25114. });
  25115. editor.on('dragend drop', () => {
  25116. isDragging = false;
  25117. });
  25118. editor.on('NodeChange', _e => {
  25119. search(contextbar.element).fold(launchContextToolbar.throttle, noop);
  25120. });
  25121. });
  25122. };
  25123. const register$8 = editor => {
  25124. const alignToolbarButtons = [
  25125. {
  25126. name: 'alignleft',
  25127. text: 'Align left',
  25128. cmd: 'JustifyLeft',
  25129. icon: 'align-left'
  25130. },
  25131. {
  25132. name: 'aligncenter',
  25133. text: 'Align center',
  25134. cmd: 'JustifyCenter',
  25135. icon: 'align-center'
  25136. },
  25137. {
  25138. name: 'alignright',
  25139. text: 'Align right',
  25140. cmd: 'JustifyRight',
  25141. icon: 'align-right'
  25142. },
  25143. {
  25144. name: 'alignjustify',
  25145. text: 'Justify',
  25146. cmd: 'JustifyFull',
  25147. icon: 'align-justify'
  25148. }
  25149. ];
  25150. each$1(alignToolbarButtons, item => {
  25151. editor.ui.registry.addToggleButton(item.name, {
  25152. tooltip: item.text,
  25153. icon: item.icon,
  25154. onAction: onActionExecCommand(editor, item.cmd),
  25155. onSetup: onSetupStateToggle(editor, item.name)
  25156. });
  25157. });
  25158. editor.ui.registry.addButton('alignnone', {
  25159. tooltip: 'No alignment',
  25160. icon: 'align-none',
  25161. onSetup: onSetupEditableToggle(editor),
  25162. onAction: onActionExecCommand(editor, 'JustifyNone')
  25163. });
  25164. };
  25165. const registerController = (editor, spec) => {
  25166. const getMenuItems = () => {
  25167. const options = spec.getOptions(editor);
  25168. const initial = spec.getCurrent(editor).map(spec.hash);
  25169. const current = value$2();
  25170. return map$2(options, value => ({
  25171. type: 'togglemenuitem',
  25172. text: spec.display(value),
  25173. onSetup: api => {
  25174. const setActive = active => {
  25175. if (active) {
  25176. current.on(oldApi => oldApi.setActive(false));
  25177. current.set(api);
  25178. }
  25179. api.setActive(active);
  25180. };
  25181. setActive(is$1(initial, spec.hash(value)));
  25182. const unbindWatcher = spec.watcher(editor, value, setActive);
  25183. return () => {
  25184. current.clear();
  25185. unbindWatcher();
  25186. };
  25187. },
  25188. onAction: () => spec.setCurrent(editor, value)
  25189. }));
  25190. };
  25191. editor.ui.registry.addMenuButton(spec.name, {
  25192. tooltip: spec.text,
  25193. icon: spec.icon,
  25194. fetch: callback => callback(getMenuItems()),
  25195. onSetup: spec.onToolbarSetup
  25196. });
  25197. editor.ui.registry.addNestedMenuItem(spec.name, {
  25198. type: 'nestedmenuitem',
  25199. text: spec.text,
  25200. getSubmenuItems: getMenuItems,
  25201. onSetup: spec.onMenuSetup
  25202. });
  25203. };
  25204. const lineHeightSpec = editor => ({
  25205. name: 'lineheight',
  25206. text: 'Line height',
  25207. icon: 'line-height',
  25208. getOptions: getLineHeightFormats,
  25209. hash: input => normalise(input, [
  25210. 'fixed',
  25211. 'relative',
  25212. 'empty'
  25213. ]).getOr(input),
  25214. display: identity,
  25215. watcher: (editor, value, callback) => editor.formatter.formatChanged('lineheight', callback, false, { value }).unbind,
  25216. getCurrent: editor => Optional.from(editor.queryCommandValue('LineHeight')),
  25217. setCurrent: (editor, value) => editor.execCommand('LineHeight', false, value),
  25218. onToolbarSetup: onSetupEditableToggle(editor),
  25219. onMenuSetup: onSetupEditableToggle(editor)
  25220. });
  25221. const languageSpec = editor => {
  25222. const settingsOpt = Optional.from(getContentLanguages(editor));
  25223. return settingsOpt.map(settings => ({
  25224. name: 'language',
  25225. text: 'Language',
  25226. icon: 'language',
  25227. getOptions: constant$1(settings),
  25228. hash: input => isUndefined(input.customCode) ? input.code : `${ input.code }/${ input.customCode }`,
  25229. display: input => input.title,
  25230. watcher: (editor, value, callback) => {
  25231. var _a;
  25232. return editor.formatter.formatChanged('lang', callback, false, {
  25233. value: value.code,
  25234. customValue: (_a = value.customCode) !== null && _a !== void 0 ? _a : null
  25235. }).unbind;
  25236. },
  25237. getCurrent: editor => {
  25238. const node = SugarElement.fromDom(editor.selection.getNode());
  25239. return closest$4(node, n => Optional.some(n).filter(isElement$1).bind(ele => {
  25240. const codeOpt = getOpt(ele, 'lang');
  25241. return codeOpt.map(code => {
  25242. const customCode = getOpt(ele, 'data-mce-lang').getOrUndefined();
  25243. return {
  25244. code,
  25245. customCode,
  25246. title: ''
  25247. };
  25248. });
  25249. }));
  25250. },
  25251. setCurrent: (editor, lang) => editor.execCommand('Lang', false, lang),
  25252. onToolbarSetup: api => {
  25253. const unbinder = unbindable();
  25254. api.setActive(editor.formatter.match('lang', {}, undefined, true));
  25255. unbinder.set(editor.formatter.formatChanged('lang', api.setActive, true));
  25256. return composeUnbinders(unbinder.clear, onSetupEditableToggle(editor)(api));
  25257. },
  25258. onMenuSetup: onSetupEditableToggle(editor)
  25259. }));
  25260. };
  25261. const register$7 = editor => {
  25262. registerController(editor, lineHeightSpec(editor));
  25263. languageSpec(editor).each(spec => registerController(editor, spec));
  25264. };
  25265. const register$6 = (editor, backstage) => {
  25266. createAlignMenu(editor, backstage);
  25267. createFontFamilyMenu(editor, backstage);
  25268. createStylesMenu(editor, backstage);
  25269. createBlocksMenu(editor, backstage);
  25270. createFontSizeMenu(editor, backstage);
  25271. };
  25272. const onSetupOutdentState = editor => onSetupEvent(editor, 'NodeChange', api => {
  25273. api.setEnabled(editor.queryCommandState('outdent') && editor.selection.isEditable());
  25274. });
  25275. const registerButtons$2 = editor => {
  25276. editor.ui.registry.addButton('outdent', {
  25277. tooltip: 'Decrease indent',
  25278. icon: 'outdent',
  25279. onSetup: onSetupOutdentState(editor),
  25280. onAction: onActionExecCommand(editor, 'outdent')
  25281. });
  25282. editor.ui.registry.addButton('indent', {
  25283. tooltip: 'Increase indent',
  25284. icon: 'indent',
  25285. onSetup: onSetupEditableToggle(editor),
  25286. onAction: onActionExecCommand(editor, 'indent')
  25287. });
  25288. };
  25289. const register$5 = editor => {
  25290. registerButtons$2(editor);
  25291. };
  25292. const makeSetupHandler = (editor, pasteAsText) => api => {
  25293. api.setActive(pasteAsText.get());
  25294. const pastePlainTextToggleHandler = e => {
  25295. pasteAsText.set(e.state);
  25296. api.setActive(e.state);
  25297. };
  25298. editor.on('PastePlainTextToggle', pastePlainTextToggleHandler);
  25299. return composeUnbinders(() => editor.off('PastePlainTextToggle', pastePlainTextToggleHandler), onSetupEditableToggle(editor)(api));
  25300. };
  25301. const register$4 = editor => {
  25302. const pasteAsText = Cell(getPasteAsText(editor));
  25303. const onAction = () => editor.execCommand('mceTogglePlainTextPaste');
  25304. editor.ui.registry.addToggleButton('pastetext', {
  25305. active: false,
  25306. icon: 'paste-text',
  25307. tooltip: 'Paste as text',
  25308. onAction,
  25309. onSetup: makeSetupHandler(editor, pasteAsText)
  25310. });
  25311. editor.ui.registry.addToggleMenuItem('pastetext', {
  25312. text: 'Paste as text',
  25313. icon: 'paste-text',
  25314. onAction,
  25315. onSetup: makeSetupHandler(editor, pasteAsText)
  25316. });
  25317. };
  25318. const onActionToggleFormat = (editor, fmt) => () => {
  25319. editor.execCommand('mceToggleFormat', false, fmt);
  25320. };
  25321. const registerFormatButtons = editor => {
  25322. global$1.each([
  25323. {
  25324. name: 'bold',
  25325. text: 'Bold',
  25326. icon: 'bold'
  25327. },
  25328. {
  25329. name: 'italic',
  25330. text: 'Italic',
  25331. icon: 'italic'
  25332. },
  25333. {
  25334. name: 'underline',
  25335. text: 'Underline',
  25336. icon: 'underline'
  25337. },
  25338. {
  25339. name: 'strikethrough',
  25340. text: 'Strikethrough',
  25341. icon: 'strike-through'
  25342. },
  25343. {
  25344. name: 'subscript',
  25345. text: 'Subscript',
  25346. icon: 'subscript'
  25347. },
  25348. {
  25349. name: 'superscript',
  25350. text: 'Superscript',
  25351. icon: 'superscript'
  25352. }
  25353. ], (btn, _idx) => {
  25354. editor.ui.registry.addToggleButton(btn.name, {
  25355. tooltip: btn.text,
  25356. icon: btn.icon,
  25357. onSetup: onSetupStateToggle(editor, btn.name),
  25358. onAction: onActionToggleFormat(editor, btn.name)
  25359. });
  25360. });
  25361. for (let i = 1; i <= 6; i++) {
  25362. const name = 'h' + i;
  25363. editor.ui.registry.addToggleButton(name, {
  25364. text: name.toUpperCase(),
  25365. tooltip: 'Heading ' + i,
  25366. onSetup: onSetupStateToggle(editor, name),
  25367. onAction: onActionToggleFormat(editor, name)
  25368. });
  25369. }
  25370. };
  25371. const registerCommandButtons = editor => {
  25372. global$1.each([
  25373. {
  25374. name: 'copy',
  25375. text: 'Copy',
  25376. action: 'Copy',
  25377. icon: 'copy'
  25378. },
  25379. {
  25380. name: 'help',
  25381. text: 'Help',
  25382. action: 'mceHelp',
  25383. icon: 'help'
  25384. },
  25385. {
  25386. name: 'selectall',
  25387. text: 'Select all',
  25388. action: 'SelectAll',
  25389. icon: 'select-all'
  25390. },
  25391. {
  25392. name: 'newdocument',
  25393. text: 'New document',
  25394. action: 'mceNewDocument',
  25395. icon: 'new-document'
  25396. },
  25397. {
  25398. name: 'print',
  25399. text: 'Print',
  25400. action: 'mcePrint',
  25401. icon: 'print'
  25402. }
  25403. ], btn => {
  25404. editor.ui.registry.addButton(btn.name, {
  25405. tooltip: btn.text,
  25406. icon: btn.icon,
  25407. onAction: onActionExecCommand(editor, btn.action)
  25408. });
  25409. });
  25410. global$1.each([
  25411. {
  25412. name: 'cut',
  25413. text: 'Cut',
  25414. action: 'Cut',
  25415. icon: 'cut'
  25416. },
  25417. {
  25418. name: 'paste',
  25419. text: 'Paste',
  25420. action: 'Paste',
  25421. icon: 'paste'
  25422. },
  25423. {
  25424. name: 'removeformat',
  25425. text: 'Clear formatting',
  25426. action: 'RemoveFormat',
  25427. icon: 'remove-formatting'
  25428. },
  25429. {
  25430. name: 'remove',
  25431. text: 'Remove',
  25432. action: 'Delete',
  25433. icon: 'remove'
  25434. },
  25435. {
  25436. name: 'hr',
  25437. text: 'Horizontal line',
  25438. action: 'InsertHorizontalRule',
  25439. icon: 'horizontal-rule'
  25440. }
  25441. ], btn => {
  25442. editor.ui.registry.addButton(btn.name, {
  25443. tooltip: btn.text,
  25444. icon: btn.icon,
  25445. onSetup: onSetupEditableToggle(editor),
  25446. onAction: onActionExecCommand(editor, btn.action)
  25447. });
  25448. });
  25449. };
  25450. const registerCommandToggleButtons = editor => {
  25451. global$1.each([{
  25452. name: 'blockquote',
  25453. text: 'Blockquote',
  25454. action: 'mceBlockQuote',
  25455. icon: 'quote'
  25456. }], btn => {
  25457. editor.ui.registry.addToggleButton(btn.name, {
  25458. tooltip: btn.text,
  25459. icon: btn.icon,
  25460. onAction: onActionExecCommand(editor, btn.action),
  25461. onSetup: onSetupStateToggle(editor, btn.name)
  25462. });
  25463. });
  25464. };
  25465. const registerButtons$1 = editor => {
  25466. registerFormatButtons(editor);
  25467. registerCommandButtons(editor);
  25468. registerCommandToggleButtons(editor);
  25469. };
  25470. const registerMenuItems$2 = editor => {
  25471. global$1.each([
  25472. {
  25473. name: 'newdocument',
  25474. text: 'New document',
  25475. action: 'mceNewDocument',
  25476. icon: 'new-document'
  25477. },
  25478. {
  25479. name: 'copy',
  25480. text: 'Copy',
  25481. action: 'Copy',
  25482. icon: 'copy',
  25483. shortcut: 'Meta+C'
  25484. },
  25485. {
  25486. name: 'selectall',
  25487. text: 'Select all',
  25488. action: 'SelectAll',
  25489. icon: 'select-all',
  25490. shortcut: 'Meta+A'
  25491. },
  25492. {
  25493. name: 'print',
  25494. text: 'Print...',
  25495. action: 'mcePrint',
  25496. icon: 'print',
  25497. shortcut: 'Meta+P'
  25498. }
  25499. ], menuitem => {
  25500. editor.ui.registry.addMenuItem(menuitem.name, {
  25501. text: menuitem.text,
  25502. icon: menuitem.icon,
  25503. shortcut: menuitem.shortcut,
  25504. onAction: onActionExecCommand(editor, menuitem.action)
  25505. });
  25506. });
  25507. global$1.each([
  25508. {
  25509. name: 'bold',
  25510. text: 'Bold',
  25511. action: 'Bold',
  25512. icon: 'bold',
  25513. shortcut: 'Meta+B'
  25514. },
  25515. {
  25516. name: 'italic',
  25517. text: 'Italic',
  25518. action: 'Italic',
  25519. icon: 'italic',
  25520. shortcut: 'Meta+I'
  25521. },
  25522. {
  25523. name: 'underline',
  25524. text: 'Underline',
  25525. action: 'Underline',
  25526. icon: 'underline',
  25527. shortcut: 'Meta+U'
  25528. },
  25529. {
  25530. name: 'strikethrough',
  25531. text: 'Strikethrough',
  25532. action: 'Strikethrough',
  25533. icon: 'strike-through'
  25534. },
  25535. {
  25536. name: 'subscript',
  25537. text: 'Subscript',
  25538. action: 'Subscript',
  25539. icon: 'subscript'
  25540. },
  25541. {
  25542. name: 'superscript',
  25543. text: 'Superscript',
  25544. action: 'Superscript',
  25545. icon: 'superscript'
  25546. },
  25547. {
  25548. name: 'removeformat',
  25549. text: 'Clear formatting',
  25550. action: 'RemoveFormat',
  25551. icon: 'remove-formatting'
  25552. },
  25553. {
  25554. name: 'cut',
  25555. text: 'Cut',
  25556. action: 'Cut',
  25557. icon: 'cut',
  25558. shortcut: 'Meta+X'
  25559. },
  25560. {
  25561. name: 'paste',
  25562. text: 'Paste',
  25563. action: 'Paste',
  25564. icon: 'paste',
  25565. shortcut: 'Meta+V'
  25566. },
  25567. {
  25568. name: 'hr',
  25569. text: 'Horizontal line',
  25570. action: 'InsertHorizontalRule',
  25571. icon: 'horizontal-rule'
  25572. }
  25573. ], menuitem => {
  25574. editor.ui.registry.addMenuItem(menuitem.name, {
  25575. text: menuitem.text,
  25576. icon: menuitem.icon,
  25577. shortcut: menuitem.shortcut,
  25578. onSetup: onSetupEditableToggle(editor),
  25579. onAction: onActionExecCommand(editor, menuitem.action)
  25580. });
  25581. });
  25582. editor.ui.registry.addMenuItem('codeformat', {
  25583. text: 'Code',
  25584. icon: 'sourcecode',
  25585. onSetup: onSetupEditableToggle(editor),
  25586. onAction: onActionToggleFormat(editor, 'code')
  25587. });
  25588. };
  25589. const register$3 = editor => {
  25590. registerButtons$1(editor);
  25591. registerMenuItems$2(editor);
  25592. };
  25593. const onSetupUndoRedoState = (editor, type) => onSetupEvent(editor, 'Undo Redo AddUndo TypingUndo ClearUndos SwitchMode', api => {
  25594. api.setEnabled(!editor.mode.isReadOnly() && editor.undoManager[type]());
  25595. });
  25596. const registerMenuItems$1 = editor => {
  25597. editor.ui.registry.addMenuItem('undo', {
  25598. text: 'Undo',
  25599. icon: 'undo',
  25600. shortcut: 'Meta+Z',
  25601. onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
  25602. onAction: onActionExecCommand(editor, 'undo')
  25603. });
  25604. editor.ui.registry.addMenuItem('redo', {
  25605. text: 'Redo',
  25606. icon: 'redo',
  25607. shortcut: 'Meta+Y',
  25608. onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
  25609. onAction: onActionExecCommand(editor, 'redo')
  25610. });
  25611. };
  25612. const registerButtons = editor => {
  25613. editor.ui.registry.addButton('undo', {
  25614. tooltip: 'Undo',
  25615. icon: 'undo',
  25616. enabled: false,
  25617. onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
  25618. onAction: onActionExecCommand(editor, 'undo')
  25619. });
  25620. editor.ui.registry.addButton('redo', {
  25621. tooltip: 'Redo',
  25622. icon: 'redo',
  25623. enabled: false,
  25624. onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
  25625. onAction: onActionExecCommand(editor, 'redo')
  25626. });
  25627. };
  25628. const register$2 = editor => {
  25629. registerMenuItems$1(editor);
  25630. registerButtons(editor);
  25631. };
  25632. const onSetupVisualAidState = editor => onSetupEvent(editor, 'VisualAid', api => {
  25633. api.setActive(editor.hasVisual);
  25634. });
  25635. const registerMenuItems = editor => {
  25636. editor.ui.registry.addToggleMenuItem('visualaid', {
  25637. text: 'Visual aids',
  25638. onSetup: onSetupVisualAidState(editor),
  25639. onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
  25640. });
  25641. };
  25642. const registerToolbarButton = editor => {
  25643. editor.ui.registry.addButton('visualaid', {
  25644. tooltip: 'Visual aids',
  25645. text: 'Visual aids',
  25646. onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
  25647. });
  25648. };
  25649. const register$1 = editor => {
  25650. registerToolbarButton(editor);
  25651. registerMenuItems(editor);
  25652. };
  25653. const setup$6 = (editor, backstage) => {
  25654. register$8(editor);
  25655. register$3(editor);
  25656. register$6(editor, backstage);
  25657. register$2(editor);
  25658. register$c(editor);
  25659. register$1(editor);
  25660. register$5(editor);
  25661. register$7(editor);
  25662. register$4(editor);
  25663. };
  25664. const patchPipeConfig = config => isString(config) ? config.split(/[ ,]/) : config;
  25665. const option = name => editor => editor.options.get(name);
  25666. const register = editor => {
  25667. const registerOption = editor.options.register;
  25668. registerOption('contextmenu_avoid_overlap', {
  25669. processor: 'string',
  25670. default: ''
  25671. });
  25672. registerOption('contextmenu_never_use_native', {
  25673. processor: 'boolean',
  25674. default: false
  25675. });
  25676. registerOption('contextmenu', {
  25677. processor: value => {
  25678. if (value === false) {
  25679. return {
  25680. value: [],
  25681. valid: true
  25682. };
  25683. } else if (isString(value) || isArrayOf(value, isString)) {
  25684. return {
  25685. value: patchPipeConfig(value),
  25686. valid: true
  25687. };
  25688. } else {
  25689. return {
  25690. valid: false,
  25691. message: 'Must be false or a string.'
  25692. };
  25693. }
  25694. },
  25695. default: 'link linkchecker image editimage table spellchecker configurepermanentpen'
  25696. });
  25697. };
  25698. const shouldNeverUseNative = option('contextmenu_never_use_native');
  25699. const getAvoidOverlapSelector = option('contextmenu_avoid_overlap');
  25700. const isContextMenuDisabled = editor => getContextMenu(editor).length === 0;
  25701. const getContextMenu = editor => {
  25702. const contextMenus = editor.ui.registry.getAll().contextMenus;
  25703. const contextMenu = editor.options.get('contextmenu');
  25704. if (editor.options.isSet('contextmenu')) {
  25705. return contextMenu;
  25706. } else {
  25707. return filter$2(contextMenu, item => has$2(contextMenus, item));
  25708. }
  25709. };
  25710. const nu = (x, y) => ({
  25711. type: 'makeshift',
  25712. x,
  25713. y
  25714. });
  25715. const transpose = (pos, dx, dy) => {
  25716. return nu(pos.x + dx, pos.y + dy);
  25717. };
  25718. const isTouchEvent$1 = e => e.type === 'longpress' || e.type.indexOf('touch') === 0;
  25719. const fromPageXY = e => {
  25720. if (isTouchEvent$1(e)) {
  25721. const touch = e.touches[0];
  25722. return nu(touch.pageX, touch.pageY);
  25723. } else {
  25724. return nu(e.pageX, e.pageY);
  25725. }
  25726. };
  25727. const fromClientXY = e => {
  25728. if (isTouchEvent$1(e)) {
  25729. const touch = e.touches[0];
  25730. return nu(touch.clientX, touch.clientY);
  25731. } else {
  25732. return nu(e.clientX, e.clientY);
  25733. }
  25734. };
  25735. const transposeContentAreaContainer = (element, pos) => {
  25736. const containerPos = global$7.DOM.getPos(element);
  25737. return transpose(pos, containerPos.x, containerPos.y);
  25738. };
  25739. const getPointAnchor = (editor, e) => {
  25740. if (e.type === 'contextmenu' || e.type === 'longpress') {
  25741. if (editor.inline) {
  25742. return fromPageXY(e);
  25743. } else {
  25744. return transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e));
  25745. }
  25746. } else {
  25747. return getSelectionAnchor(editor);
  25748. }
  25749. };
  25750. const getSelectionAnchor = editor => {
  25751. return {
  25752. type: 'selection',
  25753. root: SugarElement.fromDom(editor.selection.getNode())
  25754. };
  25755. };
  25756. const getNodeAnchor = editor => ({
  25757. type: 'node',
  25758. node: Optional.some(SugarElement.fromDom(editor.selection.getNode())),
  25759. root: SugarElement.fromDom(editor.getBody())
  25760. });
  25761. const getAnchorSpec$1 = (editor, e, anchorType) => {
  25762. switch (anchorType) {
  25763. case 'node':
  25764. return getNodeAnchor(editor);
  25765. case 'point':
  25766. return getPointAnchor(editor, e);
  25767. case 'selection':
  25768. return getSelectionAnchor(editor);
  25769. }
  25770. };
  25771. const initAndShow$1 = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
  25772. const items = buildMenu();
  25773. const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
  25774. build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
  25775. isHorizontalMenu: false,
  25776. search: Optional.none()
  25777. }).map(menuData => {
  25778. e.preventDefault();
  25779. InlineView.showMenuAt(contextmenu, { anchor: anchorSpec }, {
  25780. menu: { markers: markers('normal') },
  25781. data: menuData
  25782. });
  25783. });
  25784. };
  25785. const layouts = {
  25786. onLtr: () => [
  25787. south$2,
  25788. southeast$2,
  25789. southwest$2,
  25790. northeast$2,
  25791. northwest$2,
  25792. north$2,
  25793. north,
  25794. south,
  25795. northeast,
  25796. southeast,
  25797. northwest,
  25798. southwest
  25799. ],
  25800. onRtl: () => [
  25801. south$2,
  25802. southwest$2,
  25803. southeast$2,
  25804. northwest$2,
  25805. northeast$2,
  25806. north$2,
  25807. north,
  25808. south,
  25809. northwest,
  25810. southwest,
  25811. northeast,
  25812. southeast
  25813. ]
  25814. };
  25815. const bubbleSize = 12;
  25816. const bubbleAlignments = {
  25817. valignCentre: [],
  25818. alignCentre: [],
  25819. alignLeft: ['tox-pop--align-left'],
  25820. alignRight: ['tox-pop--align-right'],
  25821. right: ['tox-pop--right'],
  25822. left: ['tox-pop--left'],
  25823. bottom: ['tox-pop--bottom'],
  25824. top: ['tox-pop--top']
  25825. };
  25826. const isTouchWithinSelection = (editor, e) => {
  25827. const selection = editor.selection;
  25828. if (selection.isCollapsed() || e.touches.length < 1) {
  25829. return false;
  25830. } else {
  25831. const touch = e.touches[0];
  25832. const rng = selection.getRng();
  25833. const rngRectOpt = getFirstRect(editor.getWin(), SimSelection.domRange(rng));
  25834. return rngRectOpt.exists(rngRect => rngRect.left <= touch.clientX && rngRect.right >= touch.clientX && rngRect.top <= touch.clientY && rngRect.bottom >= touch.clientY);
  25835. }
  25836. };
  25837. const setupiOSOverrides = editor => {
  25838. const originalSelection = editor.selection.getRng();
  25839. const selectionReset = () => {
  25840. global$9.setEditorTimeout(editor, () => {
  25841. editor.selection.setRng(originalSelection);
  25842. }, 10);
  25843. unbindEventListeners();
  25844. };
  25845. editor.once('touchend', selectionReset);
  25846. const preventMousedown = e => {
  25847. e.preventDefault();
  25848. e.stopImmediatePropagation();
  25849. };
  25850. editor.on('mousedown', preventMousedown, true);
  25851. const clearSelectionReset = () => unbindEventListeners();
  25852. editor.once('longpresscancel', clearSelectionReset);
  25853. const unbindEventListeners = () => {
  25854. editor.off('touchend', selectionReset);
  25855. editor.off('longpresscancel', clearSelectionReset);
  25856. editor.off('mousedown', preventMousedown);
  25857. };
  25858. };
  25859. const getAnchorSpec = (editor, e, anchorType) => {
  25860. const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
  25861. const bubbleYOffset = anchorType === 'point' ? bubbleSize : 0;
  25862. return {
  25863. bubble: nu$5(0, bubbleYOffset, bubbleAlignments),
  25864. layouts,
  25865. overrides: {
  25866. maxWidthFunction: expandable(),
  25867. maxHeightFunction: expandable$1()
  25868. },
  25869. ...anchorSpec
  25870. };
  25871. };
  25872. const show = (editor, e, items, backstage, contextmenu, anchorType, highlightImmediately) => {
  25873. const anchorSpec = getAnchorSpec(editor, e, anchorType);
  25874. build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, {
  25875. isHorizontalMenu: true,
  25876. search: Optional.none()
  25877. }).map(menuData => {
  25878. e.preventDefault();
  25879. const highlightOnOpen = highlightImmediately ? HighlightOnOpen.HighlightMenuAndItem : HighlightOnOpen.HighlightNone;
  25880. InlineView.showMenuWithinBounds(contextmenu, { anchor: anchorSpec }, {
  25881. menu: {
  25882. markers: markers('normal'),
  25883. highlightOnOpen
  25884. },
  25885. data: menuData,
  25886. type: 'horizontal'
  25887. }, () => Optional.some(getContextToolbarBounds(editor, backstage.shared, anchorType === 'node' ? 'node' : 'selection')));
  25888. editor.dispatch(hideContextToolbarEvent);
  25889. });
  25890. };
  25891. const initAndShow = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
  25892. const detection = detect$2();
  25893. const isiOS = detection.os.isiOS();
  25894. const isMacOS = detection.os.isMacOS();
  25895. const isAndroid = detection.os.isAndroid();
  25896. const isTouch = detection.deviceType.isTouch();
  25897. const shouldHighlightImmediately = () => !(isAndroid || isiOS || isMacOS && isTouch);
  25898. const open = () => {
  25899. const items = buildMenu();
  25900. show(editor, e, items, backstage, contextmenu, anchorType, shouldHighlightImmediately());
  25901. };
  25902. if ((isMacOS || isiOS) && anchorType !== 'node') {
  25903. const openiOS = () => {
  25904. setupiOSOverrides(editor);
  25905. open();
  25906. };
  25907. if (isTouchWithinSelection(editor, e)) {
  25908. openiOS();
  25909. } else {
  25910. editor.once('selectionchange', openiOS);
  25911. editor.once('touchend', () => editor.off('selectionchange', openiOS));
  25912. }
  25913. } else {
  25914. open();
  25915. }
  25916. };
  25917. const isSeparator = item => isString(item) ? item === '|' : item.type === 'separator';
  25918. const separator = { type: 'separator' };
  25919. const makeContextItem = item => {
  25920. const commonMenuItem = item => ({
  25921. text: item.text,
  25922. icon: item.icon,
  25923. enabled: item.enabled,
  25924. shortcut: item.shortcut
  25925. });
  25926. if (isString(item)) {
  25927. return item;
  25928. } else {
  25929. switch (item.type) {
  25930. case 'separator':
  25931. return separator;
  25932. case 'submenu':
  25933. return {
  25934. type: 'nestedmenuitem',
  25935. ...commonMenuItem(item),
  25936. getSubmenuItems: () => {
  25937. const items = item.getSubmenuItems();
  25938. if (isString(items)) {
  25939. return items;
  25940. } else {
  25941. return map$2(items, makeContextItem);
  25942. }
  25943. }
  25944. };
  25945. default:
  25946. const commonItem = item;
  25947. return {
  25948. type: 'menuitem',
  25949. ...commonMenuItem(commonItem),
  25950. onAction: noarg(commonItem.onAction)
  25951. };
  25952. }
  25953. }
  25954. };
  25955. const addContextMenuGroup = (xs, groupItems) => {
  25956. if (groupItems.length === 0) {
  25957. return xs;
  25958. }
  25959. const lastMenuItem = last$1(xs).filter(item => !isSeparator(item));
  25960. const before = lastMenuItem.fold(() => [], _ => [separator]);
  25961. return xs.concat(before).concat(groupItems).concat([separator]);
  25962. };
  25963. const generateContextMenu = (contextMenus, menuConfig, selectedElement) => {
  25964. const sections = foldl(menuConfig, (acc, name) => {
  25965. return get$g(contextMenus, name.toLowerCase()).map(menu => {
  25966. const items = menu.update(selectedElement);
  25967. if (isString(items) && isNotEmpty(trim$1(items))) {
  25968. return addContextMenuGroup(acc, items.split(' '));
  25969. } else if (isArray(items) && items.length > 0) {
  25970. const allItems = map$2(items, makeContextItem);
  25971. return addContextMenuGroup(acc, allItems);
  25972. } else {
  25973. return acc;
  25974. }
  25975. }).getOrThunk(() => acc.concat([name]));
  25976. }, []);
  25977. if (sections.length > 0 && isSeparator(sections[sections.length - 1])) {
  25978. sections.pop();
  25979. }
  25980. return sections;
  25981. };
  25982. const isNativeOverrideKeyEvent = (editor, e) => e.ctrlKey && !shouldNeverUseNative(editor);
  25983. const isTouchEvent = e => e.type === 'longpress' || has$2(e, 'touches');
  25984. const isTriggeredByKeyboard = (editor, e) => !isTouchEvent(e) && (e.button !== 2 || e.target === editor.getBody() && e.pointerType === '');
  25985. const getSelectedElement = (editor, e) => isTriggeredByKeyboard(editor, e) ? editor.selection.getStart(true) : e.target;
  25986. const getAnchorType = (editor, e) => {
  25987. const selector = getAvoidOverlapSelector(editor);
  25988. const anchorType = isTriggeredByKeyboard(editor, e) ? 'selection' : 'point';
  25989. if (isNotEmpty(selector)) {
  25990. const target = getSelectedElement(editor, e);
  25991. const selectorExists = closest(SugarElement.fromDom(target), selector);
  25992. return selectorExists ? 'node' : anchorType;
  25993. } else {
  25994. return anchorType;
  25995. }
  25996. };
  25997. const setup$5 = (editor, lazySink, backstage) => {
  25998. const detection = detect$2();
  25999. const isTouch = detection.deviceType.isTouch;
  26000. const contextmenu = build$1(InlineView.sketch({
  26001. dom: { tag: 'div' },
  26002. lazySink,
  26003. onEscape: () => editor.focus(),
  26004. onShow: () => backstage.setContextMenuState(true),
  26005. onHide: () => backstage.setContextMenuState(false),
  26006. fireDismissalEventInstead: {},
  26007. inlineBehaviours: derive$1([config('dismissContextMenu', [run$1(dismissRequested(), (comp, _se) => {
  26008. Sandboxing.close(comp);
  26009. editor.focus();
  26010. })])])
  26011. }));
  26012. const hideContextMenu = () => InlineView.hide(contextmenu);
  26013. const showContextMenu = e => {
  26014. if (shouldNeverUseNative(editor)) {
  26015. e.preventDefault();
  26016. }
  26017. if (isNativeOverrideKeyEvent(editor, e) || isContextMenuDisabled(editor)) {
  26018. return;
  26019. }
  26020. const anchorType = getAnchorType(editor, e);
  26021. const buildMenu = () => {
  26022. const selectedElement = getSelectedElement(editor, e);
  26023. const registry = editor.ui.registry.getAll();
  26024. const menuConfig = getContextMenu(editor);
  26025. return generateContextMenu(registry.contextMenus, menuConfig, selectedElement);
  26026. };
  26027. const initAndShow$2 = isTouch() ? initAndShow : initAndShow$1;
  26028. initAndShow$2(editor, e, buildMenu, backstage, contextmenu, anchorType);
  26029. };
  26030. editor.on('init', () => {
  26031. const hideEvents = 'ResizeEditor ScrollContent ScrollWindow longpresscancel' + (isTouch() ? '' : ' ResizeWindow');
  26032. editor.on(hideEvents, hideContextMenu);
  26033. editor.on('longpress contextmenu', showContextMenu);
  26034. });
  26035. };
  26036. const adt = Adt.generate([
  26037. {
  26038. offset: [
  26039. 'x',
  26040. 'y'
  26041. ]
  26042. },
  26043. {
  26044. absolute: [
  26045. 'x',
  26046. 'y'
  26047. ]
  26048. },
  26049. {
  26050. fixed: [
  26051. 'x',
  26052. 'y'
  26053. ]
  26054. }
  26055. ]);
  26056. const subtract = change => point => point.translate(-change.left, -change.top);
  26057. const add = change => point => point.translate(change.left, change.top);
  26058. const transform = changes => (x, y) => foldl(changes, (rest, f) => f(rest), SugarPosition(x, y));
  26059. const asFixed = (coord, scroll, origin) => coord.fold(transform([
  26060. add(origin),
  26061. subtract(scroll)
  26062. ]), transform([subtract(scroll)]), transform([]));
  26063. const asAbsolute = (coord, scroll, origin) => coord.fold(transform([add(origin)]), transform([]), transform([add(scroll)]));
  26064. const asOffset = (coord, scroll, origin) => coord.fold(transform([]), transform([subtract(origin)]), transform([
  26065. add(scroll),
  26066. subtract(origin)
  26067. ]));
  26068. const withinRange = (coord1, coord2, xRange, yRange, scroll, origin) => {
  26069. const a1 = asAbsolute(coord1, scroll, origin);
  26070. const a2 = asAbsolute(coord2, scroll, origin);
  26071. return Math.abs(a1.left - a2.left) <= xRange && Math.abs(a1.top - a2.top) <= yRange;
  26072. };
  26073. const getDeltas = (coord1, coord2, xRange, yRange, scroll, origin) => {
  26074. const a1 = asAbsolute(coord1, scroll, origin);
  26075. const a2 = asAbsolute(coord2, scroll, origin);
  26076. const left = Math.abs(a1.left - a2.left);
  26077. const top = Math.abs(a1.top - a2.top);
  26078. return SugarPosition(left, top);
  26079. };
  26080. const toStyles = (coord, scroll, origin) => {
  26081. const stylesOpt = coord.fold((x, y) => ({
  26082. position: Optional.some('absolute'),
  26083. left: Optional.some(x + 'px'),
  26084. top: Optional.some(y + 'px')
  26085. }), (x, y) => ({
  26086. position: Optional.some('absolute'),
  26087. left: Optional.some(x - origin.left + 'px'),
  26088. top: Optional.some(y - origin.top + 'px')
  26089. }), (x, y) => ({
  26090. position: Optional.some('fixed'),
  26091. left: Optional.some(x + 'px'),
  26092. top: Optional.some(y + 'px')
  26093. }));
  26094. return {
  26095. right: Optional.none(),
  26096. bottom: Optional.none(),
  26097. ...stylesOpt
  26098. };
  26099. };
  26100. const translate = (coord, deltaX, deltaY) => coord.fold((x, y) => offset(x + deltaX, y + deltaY), (x, y) => absolute(x + deltaX, y + deltaY), (x, y) => fixed(x + deltaX, y + deltaY));
  26101. const absorb = (partialCoord, originalCoord, scroll, origin) => {
  26102. const absorbOne = (stencil, nu) => (optX, optY) => {
  26103. const original = stencil(originalCoord, scroll, origin);
  26104. return nu(optX.getOr(original.left), optY.getOr(original.top));
  26105. };
  26106. return partialCoord.fold(absorbOne(asOffset, offset), absorbOne(asAbsolute, absolute), absorbOne(asFixed, fixed));
  26107. };
  26108. const offset = adt.offset;
  26109. const absolute = adt.absolute;
  26110. const fixed = adt.fixed;
  26111. const parseAttrToInt = (element, name) => {
  26112. const value = get$f(element, name);
  26113. return isUndefined(value) ? NaN : parseInt(value, 10);
  26114. };
  26115. const get = (component, snapsInfo) => {
  26116. const element = component.element;
  26117. const x = parseAttrToInt(element, snapsInfo.leftAttr);
  26118. const y = parseAttrToInt(element, snapsInfo.topAttr);
  26119. return isNaN(x) || isNaN(y) ? Optional.none() : Optional.some(SugarPosition(x, y));
  26120. };
  26121. const set = (component, snapsInfo, pt) => {
  26122. const element = component.element;
  26123. set$9(element, snapsInfo.leftAttr, pt.left + 'px');
  26124. set$9(element, snapsInfo.topAttr, pt.top + 'px');
  26125. };
  26126. const clear = (component, snapsInfo) => {
  26127. const element = component.element;
  26128. remove$7(element, snapsInfo.leftAttr);
  26129. remove$7(element, snapsInfo.topAttr);
  26130. };
  26131. const getCoords = (component, snapInfo, coord, delta) => get(component, snapInfo).fold(() => coord, fixed$1 => fixed(fixed$1.left + delta.left, fixed$1.top + delta.top));
  26132. const moveOrSnap = (component, snapInfo, coord, delta, scroll, origin) => {
  26133. const newCoord = getCoords(component, snapInfo, coord, delta);
  26134. const snap = snapInfo.mustSnap ? findClosestSnap(component, snapInfo, newCoord, scroll, origin) : findSnap(component, snapInfo, newCoord, scroll, origin);
  26135. const fixedCoord = asFixed(newCoord, scroll, origin);
  26136. set(component, snapInfo, fixedCoord);
  26137. return snap.fold(() => ({
  26138. coord: fixed(fixedCoord.left, fixedCoord.top),
  26139. extra: Optional.none()
  26140. }), spanned => ({
  26141. coord: spanned.output,
  26142. extra: spanned.extra
  26143. }));
  26144. };
  26145. const stopDrag = (component, snapInfo) => {
  26146. clear(component, snapInfo);
  26147. };
  26148. const findMatchingSnap = (snaps, newCoord, scroll, origin) => findMap(snaps, snap => {
  26149. const sensor = snap.sensor;
  26150. const inRange = withinRange(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
  26151. return inRange ? Optional.some({
  26152. output: absorb(snap.output, newCoord, scroll, origin),
  26153. extra: snap.extra
  26154. }) : Optional.none();
  26155. });
  26156. const findClosestSnap = (component, snapInfo, newCoord, scroll, origin) => {
  26157. const snaps = snapInfo.getSnapPoints(component);
  26158. const matchSnap = findMatchingSnap(snaps, newCoord, scroll, origin);
  26159. return matchSnap.orThunk(() => {
  26160. const bestSnap = foldl(snaps, (acc, snap) => {
  26161. const sensor = snap.sensor;
  26162. const deltas = getDeltas(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
  26163. return acc.deltas.fold(() => ({
  26164. deltas: Optional.some(deltas),
  26165. snap: Optional.some(snap)
  26166. }), bestDeltas => {
  26167. const currAvg = (deltas.left + deltas.top) / 2;
  26168. const bestAvg = (bestDeltas.left + bestDeltas.top) / 2;
  26169. if (currAvg <= bestAvg) {
  26170. return {
  26171. deltas: Optional.some(deltas),
  26172. snap: Optional.some(snap)
  26173. };
  26174. } else {
  26175. return acc;
  26176. }
  26177. });
  26178. }, {
  26179. deltas: Optional.none(),
  26180. snap: Optional.none()
  26181. });
  26182. return bestSnap.snap.map(snap => ({
  26183. output: absorb(snap.output, newCoord, scroll, origin),
  26184. extra: snap.extra
  26185. }));
  26186. });
  26187. };
  26188. const findSnap = (component, snapInfo, newCoord, scroll, origin) => {
  26189. const snaps = snapInfo.getSnapPoints(component);
  26190. return findMatchingSnap(snaps, newCoord, scroll, origin);
  26191. };
  26192. const snapTo$1 = (snap, scroll, origin) => ({
  26193. coord: absorb(snap.output, snap.output, scroll, origin),
  26194. extra: snap.extra
  26195. });
  26196. const snapTo = (component, dragConfig, _state, snap) => {
  26197. const target = dragConfig.getTarget(component.element);
  26198. if (dragConfig.repositionTarget) {
  26199. const doc = owner$4(component.element);
  26200. const scroll = get$b(doc);
  26201. const origin = getOrigin(target);
  26202. const snapPin = snapTo$1(snap, scroll, origin);
  26203. const styles = toStyles(snapPin.coord, scroll, origin);
  26204. setOptions(target, styles);
  26205. }
  26206. };
  26207. var DraggingApis = /*#__PURE__*/Object.freeze({
  26208. __proto__: null,
  26209. snapTo: snapTo
  26210. });
  26211. const initialAttribute = 'data-initial-z-index';
  26212. const resetZIndex = blocker => {
  26213. parent(blocker.element).filter(isElement$1).each(root => {
  26214. getOpt(root, initialAttribute).fold(() => remove$6(root, 'z-index'), zIndex => set$8(root, 'z-index', zIndex));
  26215. remove$7(root, initialAttribute);
  26216. });
  26217. };
  26218. const changeZIndex = blocker => {
  26219. parent(blocker.element).filter(isElement$1).each(root => {
  26220. getRaw(root, 'z-index').each(zindex => {
  26221. set$9(root, initialAttribute, zindex);
  26222. });
  26223. set$8(root, 'z-index', get$e(blocker.element, 'z-index'));
  26224. });
  26225. };
  26226. const instigate = (anyComponent, blocker) => {
  26227. anyComponent.getSystem().addToGui(blocker);
  26228. changeZIndex(blocker);
  26229. };
  26230. const discard = blocker => {
  26231. resetZIndex(blocker);
  26232. blocker.getSystem().removeFromGui(blocker);
  26233. };
  26234. const createComponent = (component, blockerClass, blockerEvents) => component.getSystem().build(Container.sketch({
  26235. dom: {
  26236. styles: {
  26237. 'left': '0px',
  26238. 'top': '0px',
  26239. 'width': '100%',
  26240. 'height': '100%',
  26241. 'position': 'fixed',
  26242. 'z-index': '1000000000000000'
  26243. },
  26244. classes: [blockerClass]
  26245. },
  26246. events: blockerEvents
  26247. }));
  26248. var SnapSchema = optionObjOf('snaps', [
  26249. required$1('getSnapPoints'),
  26250. onHandler('onSensor'),
  26251. required$1('leftAttr'),
  26252. required$1('topAttr'),
  26253. defaulted('lazyViewport', win),
  26254. defaulted('mustSnap', false)
  26255. ]);
  26256. const schema$6 = [
  26257. defaulted('useFixed', never),
  26258. required$1('blockerClass'),
  26259. defaulted('getTarget', identity),
  26260. defaulted('onDrag', noop),
  26261. defaulted('repositionTarget', true),
  26262. defaulted('onDrop', noop),
  26263. defaultedFunction('getBounds', win),
  26264. SnapSchema
  26265. ];
  26266. const getCurrentCoord = target => lift3(getRaw(target, 'left'), getRaw(target, 'top'), getRaw(target, 'position'), (left, top, position) => {
  26267. const nu = position === 'fixed' ? fixed : offset;
  26268. return nu(parseInt(left, 10), parseInt(top, 10));
  26269. }).getOrThunk(() => {
  26270. const location = absolute$3(target);
  26271. return absolute(location.left, location.top);
  26272. });
  26273. const clampCoords = (component, coords, scroll, origin, startData) => {
  26274. const bounds = startData.bounds;
  26275. const absoluteCoord = asAbsolute(coords, scroll, origin);
  26276. const newX = clamp(absoluteCoord.left, bounds.x, bounds.x + bounds.width - startData.width);
  26277. const newY = clamp(absoluteCoord.top, bounds.y, bounds.y + bounds.height - startData.height);
  26278. const newCoords = absolute(newX, newY);
  26279. return coords.fold(() => {
  26280. const offset$1 = asOffset(newCoords, scroll, origin);
  26281. return offset(offset$1.left, offset$1.top);
  26282. }, constant$1(newCoords), () => {
  26283. const fixed$1 = asFixed(newCoords, scroll, origin);
  26284. return fixed(fixed$1.left, fixed$1.top);
  26285. });
  26286. };
  26287. const calcNewCoord = (component, optSnaps, currentCoord, scroll, origin, delta, startData) => {
  26288. const newCoord = optSnaps.fold(() => {
  26289. const translated = translate(currentCoord, delta.left, delta.top);
  26290. const fixedCoord = asFixed(translated, scroll, origin);
  26291. return fixed(fixedCoord.left, fixedCoord.top);
  26292. }, snapInfo => {
  26293. const snapping = moveOrSnap(component, snapInfo, currentCoord, delta, scroll, origin);
  26294. snapping.extra.each(extra => {
  26295. snapInfo.onSensor(component, extra);
  26296. });
  26297. return snapping.coord;
  26298. });
  26299. return clampCoords(component, newCoord, scroll, origin, startData);
  26300. };
  26301. const dragBy = (component, dragConfig, startData, delta) => {
  26302. const target = dragConfig.getTarget(component.element);
  26303. if (dragConfig.repositionTarget) {
  26304. const doc = owner$4(component.element);
  26305. const scroll = get$b(doc);
  26306. const origin = getOrigin(target);
  26307. const currentCoord = getCurrentCoord(target);
  26308. const newCoord = calcNewCoord(component, dragConfig.snaps, currentCoord, scroll, origin, delta, startData);
  26309. const styles = toStyles(newCoord, scroll, origin);
  26310. setOptions(target, styles);
  26311. }
  26312. dragConfig.onDrag(component, target, delta);
  26313. };
  26314. const calcStartData = (dragConfig, comp) => ({
  26315. bounds: dragConfig.getBounds(),
  26316. height: getOuter$2(comp.element),
  26317. width: getOuter$1(comp.element)
  26318. });
  26319. const move = (component, dragConfig, dragState, dragMode, event) => {
  26320. const delta = dragState.update(dragMode, event);
  26321. const dragStartData = dragState.getStartData().getOrThunk(() => calcStartData(dragConfig, component));
  26322. delta.each(dlt => {
  26323. dragBy(component, dragConfig, dragStartData, dlt);
  26324. });
  26325. };
  26326. const stop = (component, blocker, dragConfig, dragState) => {
  26327. blocker.each(discard);
  26328. dragConfig.snaps.each(snapInfo => {
  26329. stopDrag(component, snapInfo);
  26330. });
  26331. const target = dragConfig.getTarget(component.element);
  26332. dragState.reset();
  26333. dragConfig.onDrop(component, target);
  26334. };
  26335. const handlers = events => (dragConfig, dragState) => {
  26336. const updateStartState = comp => {
  26337. dragState.setStartData(calcStartData(dragConfig, comp));
  26338. };
  26339. return derive$2([
  26340. run$1(windowScroll(), comp => {
  26341. dragState.getStartData().each(() => updateStartState(comp));
  26342. }),
  26343. ...events(dragConfig, dragState, updateStartState)
  26344. ]);
  26345. };
  26346. const init$3 = dragApi => derive$2([
  26347. run$1(mousedown(), dragApi.forceDrop),
  26348. run$1(mouseup(), dragApi.drop),
  26349. run$1(mousemove(), (comp, simulatedEvent) => {
  26350. dragApi.move(simulatedEvent.event);
  26351. }),
  26352. run$1(mouseout(), dragApi.delayDrop)
  26353. ]);
  26354. const getData$1 = event => Optional.from(SugarPosition(event.x, event.y));
  26355. const getDelta$1 = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
  26356. var MouseData = /*#__PURE__*/Object.freeze({
  26357. __proto__: null,
  26358. getData: getData$1,
  26359. getDelta: getDelta$1
  26360. });
  26361. const events$3 = (dragConfig, dragState, updateStartState) => [run$1(mousedown(), (component, simulatedEvent) => {
  26362. const raw = simulatedEvent.event.raw;
  26363. if (raw.button !== 0) {
  26364. return;
  26365. }
  26366. simulatedEvent.stop();
  26367. const stop$1 = () => stop(component, Optional.some(blocker), dragConfig, dragState);
  26368. const delayDrop = DelayedFunction(stop$1, 200);
  26369. const dragApi = {
  26370. drop: stop$1,
  26371. delayDrop: delayDrop.schedule,
  26372. forceDrop: stop$1,
  26373. move: event => {
  26374. delayDrop.cancel();
  26375. move(component, dragConfig, dragState, MouseData, event);
  26376. }
  26377. };
  26378. const blocker = createComponent(component, dragConfig.blockerClass, init$3(dragApi));
  26379. const start = () => {
  26380. updateStartState(component);
  26381. instigate(component, blocker);
  26382. };
  26383. start();
  26384. })];
  26385. const schema$5 = [
  26386. ...schema$6,
  26387. output$1('dragger', { handlers: handlers(events$3) })
  26388. ];
  26389. const init$2 = dragApi => derive$2([
  26390. run$1(touchstart(), dragApi.forceDrop),
  26391. run$1(touchend(), dragApi.drop),
  26392. run$1(touchcancel(), dragApi.drop),
  26393. run$1(touchmove(), (comp, simulatedEvent) => {
  26394. dragApi.move(simulatedEvent.event);
  26395. })
  26396. ]);
  26397. const getDataFrom = touches => {
  26398. const touch = touches[0];
  26399. return Optional.some(SugarPosition(touch.clientX, touch.clientY));
  26400. };
  26401. const getData = event => {
  26402. const raw = event.raw;
  26403. const touches = raw.touches;
  26404. return touches.length === 1 ? getDataFrom(touches) : Optional.none();
  26405. };
  26406. const getDelta = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
  26407. var TouchData = /*#__PURE__*/Object.freeze({
  26408. __proto__: null,
  26409. getData: getData,
  26410. getDelta: getDelta
  26411. });
  26412. const events$2 = (dragConfig, dragState, updateStartState) => {
  26413. const blockerSingleton = value$2();
  26414. const stopBlocking = component => {
  26415. stop(component, blockerSingleton.get(), dragConfig, dragState);
  26416. blockerSingleton.clear();
  26417. };
  26418. return [
  26419. run$1(touchstart(), (component, simulatedEvent) => {
  26420. simulatedEvent.stop();
  26421. const stop = () => stopBlocking(component);
  26422. const dragApi = {
  26423. drop: stop,
  26424. delayDrop: noop,
  26425. forceDrop: stop,
  26426. move: event => {
  26427. move(component, dragConfig, dragState, TouchData, event);
  26428. }
  26429. };
  26430. const blocker = createComponent(component, dragConfig.blockerClass, init$2(dragApi));
  26431. blockerSingleton.set(blocker);
  26432. const start = () => {
  26433. updateStartState(component);
  26434. instigate(component, blocker);
  26435. };
  26436. start();
  26437. }),
  26438. run$1(touchmove(), (component, simulatedEvent) => {
  26439. simulatedEvent.stop();
  26440. move(component, dragConfig, dragState, TouchData, simulatedEvent.event);
  26441. }),
  26442. run$1(touchend(), (component, simulatedEvent) => {
  26443. simulatedEvent.stop();
  26444. stopBlocking(component);
  26445. }),
  26446. run$1(touchcancel(), stopBlocking)
  26447. ];
  26448. };
  26449. const schema$4 = [
  26450. ...schema$6,
  26451. output$1('dragger', { handlers: handlers(events$2) })
  26452. ];
  26453. const events$1 = (dragConfig, dragState, updateStartState) => [
  26454. ...events$3(dragConfig, dragState, updateStartState),
  26455. ...events$2(dragConfig, dragState, updateStartState)
  26456. ];
  26457. const schema$3 = [
  26458. ...schema$6,
  26459. output$1('dragger', { handlers: handlers(events$1) })
  26460. ];
  26461. const mouse = schema$5;
  26462. const touch = schema$4;
  26463. const mouseOrTouch = schema$3;
  26464. var DraggingBranches = /*#__PURE__*/Object.freeze({
  26465. __proto__: null,
  26466. mouse: mouse,
  26467. touch: touch,
  26468. mouseOrTouch: mouseOrTouch
  26469. });
  26470. const init$1 = () => {
  26471. let previous = Optional.none();
  26472. let startData = Optional.none();
  26473. const reset = () => {
  26474. previous = Optional.none();
  26475. startData = Optional.none();
  26476. };
  26477. const calculateDelta = (mode, nu) => {
  26478. const result = previous.map(old => mode.getDelta(old, nu));
  26479. previous = Optional.some(nu);
  26480. return result;
  26481. };
  26482. const update = (mode, dragEvent) => mode.getData(dragEvent).bind(nuData => calculateDelta(mode, nuData));
  26483. const setStartData = data => {
  26484. startData = Optional.some(data);
  26485. };
  26486. const getStartData = () => startData;
  26487. const readState = constant$1({});
  26488. return nu$8({
  26489. readState,
  26490. reset,
  26491. update,
  26492. getStartData,
  26493. setStartData
  26494. });
  26495. };
  26496. var DragState = /*#__PURE__*/Object.freeze({
  26497. __proto__: null,
  26498. init: init$1
  26499. });
  26500. const Dragging = createModes({
  26501. branchKey: 'mode',
  26502. branches: DraggingBranches,
  26503. name: 'dragging',
  26504. active: {
  26505. events: (dragConfig, dragState) => {
  26506. const dragger = dragConfig.dragger;
  26507. return dragger.handlers(dragConfig, dragState);
  26508. }
  26509. },
  26510. extra: {
  26511. snap: sConfig => ({
  26512. sensor: sConfig.sensor,
  26513. range: sConfig.range,
  26514. output: sConfig.output,
  26515. extra: Optional.from(sConfig.extra)
  26516. })
  26517. },
  26518. state: DragState,
  26519. apis: DraggingApis
  26520. });
  26521. const snapWidth = 40;
  26522. const snapOffset = snapWidth / 2;
  26523. const calcSnap = (selectorOpt, td, x, y, width, height) => selectorOpt.fold(() => Dragging.snap({
  26524. sensor: absolute(x - snapOffset, y - snapOffset),
  26525. range: SugarPosition(width, height),
  26526. output: absolute(Optional.some(x), Optional.some(y)),
  26527. extra: { td }
  26528. }), selectorHandle => {
  26529. const sensorLeft = x - snapOffset;
  26530. const sensorTop = y - snapOffset;
  26531. const sensorWidth = snapWidth;
  26532. const sensorHeight = snapWidth;
  26533. const rect = selectorHandle.element.dom.getBoundingClientRect();
  26534. return Dragging.snap({
  26535. sensor: absolute(sensorLeft, sensorTop),
  26536. range: SugarPosition(sensorWidth, sensorHeight),
  26537. output: absolute(Optional.some(x - rect.width / 2), Optional.some(y - rect.height / 2)),
  26538. extra: { td }
  26539. });
  26540. });
  26541. const getSnapsConfig = (getSnapPoints, cell, onChange) => {
  26542. const isSameCell = (cellOpt, td) => cellOpt.exists(currentTd => eq(currentTd, td));
  26543. return {
  26544. getSnapPoints,
  26545. leftAttr: 'data-drag-left',
  26546. topAttr: 'data-drag-top',
  26547. onSensor: (component, extra) => {
  26548. const td = extra.td;
  26549. if (!isSameCell(cell.get(), td)) {
  26550. cell.set(td);
  26551. onChange(td);
  26552. }
  26553. },
  26554. mustSnap: true
  26555. };
  26556. };
  26557. const createSelector = snaps => record(Button.sketch({
  26558. dom: {
  26559. tag: 'div',
  26560. classes: ['tox-selector']
  26561. },
  26562. buttonBehaviours: derive$1([
  26563. Dragging.config({
  26564. mode: 'mouseOrTouch',
  26565. blockerClass: 'blocker',
  26566. snaps
  26567. }),
  26568. Unselecting.config({})
  26569. ]),
  26570. eventOrder: {
  26571. mousedown: [
  26572. 'dragging',
  26573. 'alloy.base.behaviour'
  26574. ],
  26575. touchstart: [
  26576. 'dragging',
  26577. 'alloy.base.behaviour'
  26578. ]
  26579. }
  26580. }));
  26581. const setup$4 = (editor, sink) => {
  26582. const tlTds = Cell([]);
  26583. const brTds = Cell([]);
  26584. const isVisible = Cell(false);
  26585. const startCell = value$2();
  26586. const finishCell = value$2();
  26587. const getTopLeftSnap = td => {
  26588. const box = absolute$2(td);
  26589. return calcSnap(memTopLeft.getOpt(sink), td, box.x, box.y, box.width, box.height);
  26590. };
  26591. const getTopLeftSnaps = () => map$2(tlTds.get(), td => getTopLeftSnap(td));
  26592. const getBottomRightSnap = td => {
  26593. const box = absolute$2(td);
  26594. return calcSnap(memBottomRight.getOpt(sink), td, box.right, box.bottom, box.width, box.height);
  26595. };
  26596. const getBottomRightSnaps = () => map$2(brTds.get(), td => getBottomRightSnap(td));
  26597. const topLeftSnaps = getSnapsConfig(getTopLeftSnaps, startCell, start => {
  26598. finishCell.get().each(finish => {
  26599. editor.dispatch('TableSelectorChange', {
  26600. start,
  26601. finish
  26602. });
  26603. });
  26604. });
  26605. const bottomRightSnaps = getSnapsConfig(getBottomRightSnaps, finishCell, finish => {
  26606. startCell.get().each(start => {
  26607. editor.dispatch('TableSelectorChange', {
  26608. start,
  26609. finish
  26610. });
  26611. });
  26612. });
  26613. const memTopLeft = createSelector(topLeftSnaps);
  26614. const memBottomRight = createSelector(bottomRightSnaps);
  26615. const topLeft = build$1(memTopLeft.asSpec());
  26616. const bottomRight = build$1(memBottomRight.asSpec());
  26617. const showOrHideHandle = (selector, cell, isAbove, isBelow) => {
  26618. const cellRect = cell.dom.getBoundingClientRect();
  26619. remove$6(selector.element, 'display');
  26620. const viewportHeight = defaultView(SugarElement.fromDom(editor.getBody())).dom.innerHeight;
  26621. const aboveViewport = isAbove(cellRect);
  26622. const belowViewport = isBelow(cellRect, viewportHeight);
  26623. if (aboveViewport || belowViewport) {
  26624. set$8(selector.element, 'display', 'none');
  26625. }
  26626. };
  26627. const snapTo = (selector, cell, getSnapConfig, pos) => {
  26628. const snap = getSnapConfig(cell);
  26629. Dragging.snapTo(selector, snap);
  26630. const isAbove = rect => rect[pos] < 0;
  26631. const isBelow = (rect, viewportHeight) => rect[pos] > viewportHeight;
  26632. showOrHideHandle(selector, cell, isAbove, isBelow);
  26633. };
  26634. const snapTopLeft = cell => snapTo(topLeft, cell, getTopLeftSnap, 'top');
  26635. const snapLastTopLeft = () => startCell.get().each(snapTopLeft);
  26636. const snapBottomRight = cell => snapTo(bottomRight, cell, getBottomRightSnap, 'bottom');
  26637. const snapLastBottomRight = () => finishCell.get().each(snapBottomRight);
  26638. if (detect$2().deviceType.isTouch()) {
  26639. editor.on('TableSelectionChange', e => {
  26640. if (!isVisible.get()) {
  26641. attach(sink, topLeft);
  26642. attach(sink, bottomRight);
  26643. isVisible.set(true);
  26644. }
  26645. startCell.set(e.start);
  26646. finishCell.set(e.finish);
  26647. e.otherCells.each(otherCells => {
  26648. tlTds.set(otherCells.upOrLeftCells);
  26649. brTds.set(otherCells.downOrRightCells);
  26650. snapTopLeft(e.start);
  26651. snapBottomRight(e.finish);
  26652. });
  26653. });
  26654. editor.on('ResizeEditor ResizeWindow ScrollContent', () => {
  26655. snapLastTopLeft();
  26656. snapLastBottomRight();
  26657. });
  26658. editor.on('TableSelectionClear', () => {
  26659. if (isVisible.get()) {
  26660. detach(topLeft);
  26661. detach(bottomRight);
  26662. isVisible.set(false);
  26663. }
  26664. startCell.clear();
  26665. finishCell.clear();
  26666. });
  26667. }
  26668. };
  26669. var Logo = "<svg width=\"50px\" height=\"16px\" viewBox=\"0 0 50 16\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M10.143 0c2.608.015 5.186 2.178 5.186 5.331 0 0 .077 3.812-.084 4.87-.361 2.41-2.164 4.074-4.65 4.496-1.453.284-2.523.49-3.212.623-.373.071-.634.122-.785.152-.184.038-.997.145-1.35.145-2.732 0-5.21-2.04-5.248-5.33 0 0 0-3.514.03-4.442.093-2.4 1.758-4.342 4.926-4.963 0 0 3.875-.752 4.036-.782.368-.07.775-.1 1.15-.1Zm1.826 2.8L5.83 3.989v2.393l-2.455.475v5.968l6.137-1.189V9.243l2.456-.476V2.8ZM5.83 6.382l3.682-.713v3.574l-3.682.713V6.382Zm27.173-1.64-.084-1.066h-2.226v9.132h2.456V7.743c-.008-1.151.998-2.064 2.149-2.072 1.15-.008 1.987.92 1.995 2.072v5.065h2.455V7.359c-.015-2.18-1.657-3.929-3.837-3.913a3.993 3.993 0 0 0-2.908 1.296Zm-6.3-4.266L29.16 0v2.387l-2.456.475V.476Zm0 3.2v9.132h2.456V3.676h-2.456Zm18.179 11.787L49.11 3.676H46.58l-1.612 4.527-.46 1.382-.384-1.382-1.611-4.527H39.98l3.3 9.132L42.15 16l2.732-.537ZM22.867 9.738c0 .752.568 1.075.921 1.075.353 0 .668-.047.998-.154l.537 1.765c-.23.154-.92.537-2.225.537-1.305 0-2.655-.997-2.686-2.686a136.877 136.877 0 0 1 0-4.374H18.8V3.676h1.612v-1.98l2.455-.476v2.456h2.302V5.9h-2.302v3.837Z\"/>\n</svg>\n";
  26670. const isHidden = elm => elm.nodeName === 'BR' || !!elm.getAttribute('data-mce-bogus') || elm.getAttribute('data-mce-type') === 'bookmark';
  26671. const renderElementPath = (editor, settings, providersBackstage) => {
  26672. var _a;
  26673. const delimiter = (_a = settings.delimiter) !== null && _a !== void 0 ? _a : '\u203A';
  26674. const renderElement = (name, element, index) => Button.sketch({
  26675. dom: {
  26676. tag: 'div',
  26677. classes: ['tox-statusbar__path-item'],
  26678. attributes: {
  26679. 'data-index': index,
  26680. 'aria-level': index + 1
  26681. }
  26682. },
  26683. components: [text$2(name)],
  26684. action: _btn => {
  26685. editor.focus();
  26686. editor.selection.select(element);
  26687. editor.nodeChanged();
  26688. },
  26689. buttonBehaviours: derive$1([
  26690. DisablingConfigs.button(providersBackstage.isDisabled),
  26691. receivingConfig()
  26692. ])
  26693. });
  26694. const renderDivider = () => ({
  26695. dom: {
  26696. tag: 'div',
  26697. classes: ['tox-statusbar__path-divider'],
  26698. attributes: { 'aria-hidden': true }
  26699. },
  26700. components: [text$2(` ${ delimiter } `)]
  26701. });
  26702. const renderPathData = data => foldl(data, (acc, path, index) => {
  26703. const element = renderElement(path.name, path.element, index);
  26704. if (index === 0) {
  26705. return acc.concat([element]);
  26706. } else {
  26707. return acc.concat([
  26708. renderDivider(),
  26709. element
  26710. ]);
  26711. }
  26712. }, []);
  26713. const updatePath = parents => {
  26714. const newPath = [];
  26715. let i = parents.length;
  26716. while (i-- > 0) {
  26717. const parent = parents[i];
  26718. if (parent.nodeType === 1 && !isHidden(parent)) {
  26719. const args = fireResolveName(editor, parent);
  26720. if (!args.isDefaultPrevented()) {
  26721. newPath.push({
  26722. name: args.name,
  26723. element: parent
  26724. });
  26725. }
  26726. if (args.isPropagationStopped()) {
  26727. break;
  26728. }
  26729. }
  26730. }
  26731. return newPath;
  26732. };
  26733. return {
  26734. dom: {
  26735. tag: 'div',
  26736. classes: ['tox-statusbar__path'],
  26737. attributes: { role: 'navigation' }
  26738. },
  26739. behaviours: derive$1([
  26740. Keying.config({
  26741. mode: 'flow',
  26742. selector: 'div[role=button]'
  26743. }),
  26744. Disabling.config({ disabled: providersBackstage.isDisabled }),
  26745. receivingConfig(),
  26746. Tabstopping.config({}),
  26747. Replacing.config({}),
  26748. config('elementPathEvents', [runOnAttached((comp, _e) => {
  26749. editor.shortcuts.add('alt+F11', 'focus statusbar elementpath', () => Keying.focusIn(comp));
  26750. editor.on('NodeChange', e => {
  26751. const newPath = updatePath(e.parents);
  26752. const newChildren = newPath.length > 0 ? renderPathData(newPath) : [];
  26753. Replacing.set(comp, newChildren);
  26754. });
  26755. })])
  26756. ]),
  26757. components: []
  26758. };
  26759. };
  26760. var ResizeTypes;
  26761. (function (ResizeTypes) {
  26762. ResizeTypes[ResizeTypes['None'] = 0] = 'None';
  26763. ResizeTypes[ResizeTypes['Both'] = 1] = 'Both';
  26764. ResizeTypes[ResizeTypes['Vertical'] = 2] = 'Vertical';
  26765. }(ResizeTypes || (ResizeTypes = {})));
  26766. const getDimensions = (editor, deltas, resizeType, originalHeight, originalWidth) => {
  26767. const dimensions = { height: calcCappedSize(originalHeight + deltas.top, getMinHeightOption(editor), getMaxHeightOption(editor)) };
  26768. if (resizeType === ResizeTypes.Both) {
  26769. dimensions.width = calcCappedSize(originalWidth + deltas.left, getMinWidthOption(editor), getMaxWidthOption(editor));
  26770. }
  26771. return dimensions;
  26772. };
  26773. const resize = (editor, deltas, resizeType) => {
  26774. const container = SugarElement.fromDom(editor.getContainer());
  26775. const dimensions = getDimensions(editor, deltas, resizeType, get$d(container), get$c(container));
  26776. each(dimensions, (val, dim) => {
  26777. if (isNumber(val)) {
  26778. set$8(container, dim, numToPx(val));
  26779. }
  26780. });
  26781. fireResizeEditor(editor);
  26782. };
  26783. const getResizeType = editor => {
  26784. const resize = getResize(editor);
  26785. if (resize === false) {
  26786. return ResizeTypes.None;
  26787. } else if (resize === 'both') {
  26788. return ResizeTypes.Both;
  26789. } else {
  26790. return ResizeTypes.Vertical;
  26791. }
  26792. };
  26793. const keyboardHandler = (editor, resizeType, x, y) => {
  26794. const scale = 20;
  26795. const delta = SugarPosition(x * scale, y * scale);
  26796. resize(editor, delta, resizeType);
  26797. return Optional.some(true);
  26798. };
  26799. const renderResizeHandler = (editor, providersBackstage) => {
  26800. const resizeType = getResizeType(editor);
  26801. if (resizeType === ResizeTypes.None) {
  26802. return Optional.none();
  26803. }
  26804. const resizeLabel = resizeType === ResizeTypes.Both ? 'Press the arrow keys to resize the editor.' : 'Press the Up and Down arrow keys to resize the editor.';
  26805. return Optional.some(render$3('resize-handle', {
  26806. tag: 'div',
  26807. classes: ['tox-statusbar__resize-handle'],
  26808. attributes: {
  26809. 'title': providersBackstage.translate('Resize'),
  26810. 'aria-label': providersBackstage.translate(resizeLabel)
  26811. },
  26812. behaviours: [
  26813. Dragging.config({
  26814. mode: 'mouse',
  26815. repositionTarget: false,
  26816. onDrag: (_comp, _target, delta) => resize(editor, delta, resizeType),
  26817. blockerClass: 'tox-blocker'
  26818. }),
  26819. Keying.config({
  26820. mode: 'special',
  26821. onLeft: () => keyboardHandler(editor, resizeType, -1, 0),
  26822. onRight: () => keyboardHandler(editor, resizeType, 1, 0),
  26823. onUp: () => keyboardHandler(editor, resizeType, 0, -1),
  26824. onDown: () => keyboardHandler(editor, resizeType, 0, 1)
  26825. }),
  26826. Tabstopping.config({}),
  26827. Focusing.config({})
  26828. ]
  26829. }, providersBackstage.icons));
  26830. };
  26831. const renderWordCount = (editor, providersBackstage) => {
  26832. const replaceCountText = (comp, count, mode) => Replacing.set(comp, [text$2(providersBackstage.translate([
  26833. '{0} ' + mode,
  26834. count[mode]
  26835. ]))]);
  26836. return Button.sketch({
  26837. dom: {
  26838. tag: 'button',
  26839. classes: ['tox-statusbar__wordcount']
  26840. },
  26841. components: [],
  26842. buttonBehaviours: derive$1([
  26843. DisablingConfigs.button(providersBackstage.isDisabled),
  26844. receivingConfig(),
  26845. Tabstopping.config({}),
  26846. Replacing.config({}),
  26847. Representing.config({
  26848. store: {
  26849. mode: 'memory',
  26850. initialValue: {
  26851. mode: 'words',
  26852. count: {
  26853. words: 0,
  26854. characters: 0
  26855. }
  26856. }
  26857. }
  26858. }),
  26859. config('wordcount-events', [
  26860. runOnExecute$1(comp => {
  26861. const currentVal = Representing.getValue(comp);
  26862. const newMode = currentVal.mode === 'words' ? 'characters' : 'words';
  26863. Representing.setValue(comp, {
  26864. mode: newMode,
  26865. count: currentVal.count
  26866. });
  26867. replaceCountText(comp, currentVal.count, newMode);
  26868. }),
  26869. runOnAttached(comp => {
  26870. editor.on('wordCountUpdate', e => {
  26871. const {mode} = Representing.getValue(comp);
  26872. Representing.setValue(comp, {
  26873. mode,
  26874. count: e.wordCount
  26875. });
  26876. replaceCountText(comp, e.wordCount, mode);
  26877. });
  26878. })
  26879. ])
  26880. ]),
  26881. eventOrder: {
  26882. [execute$5()]: [
  26883. 'disabling',
  26884. 'alloy.base.behaviour',
  26885. 'wordcount-events'
  26886. ]
  26887. }
  26888. });
  26889. };
  26890. const renderStatusbar = (editor, providersBackstage) => {
  26891. const renderBranding = () => {
  26892. return {
  26893. dom: {
  26894. tag: 'span',
  26895. classes: ['tox-statusbar__branding']
  26896. },
  26897. components: [{
  26898. dom: {
  26899. tag: 'a',
  26900. attributes: {
  26901. 'href': 'https://www.tiny.cloud/powered-by-tiny?utm_campaign=poweredby&utm_source=tiny&utm_medium=referral&utm_content=v6',
  26902. 'rel': 'noopener',
  26903. 'target': '_blank',
  26904. 'aria-label': global$8.translate([
  26905. 'Powered by {0}',
  26906. 'Tiny'
  26907. ])
  26908. },
  26909. innerHtml: Logo.trim()
  26910. },
  26911. behaviours: derive$1([Focusing.config({})])
  26912. }]
  26913. };
  26914. };
  26915. const renderHelpAccessibility = () => {
  26916. const shortcutText = convertText('Alt+0');
  26917. const text = `Press {0} for help`;
  26918. return {
  26919. dom: {
  26920. tag: 'div',
  26921. classes: ['tox-statusbar__help-text']
  26922. },
  26923. components: [text$2(global$8.translate([
  26924. text,
  26925. shortcutText
  26926. ]))]
  26927. };
  26928. };
  26929. const renderRightContainer = () => {
  26930. const components = [];
  26931. if (editor.hasPlugin('wordcount')) {
  26932. components.push(renderWordCount(editor, providersBackstage));
  26933. }
  26934. if (useBranding(editor)) {
  26935. components.push(renderBranding());
  26936. }
  26937. return {
  26938. dom: {
  26939. tag: 'div',
  26940. classes: ['tox-statusbar__right-container']
  26941. },
  26942. components
  26943. };
  26944. };
  26945. const getTextComponents = () => {
  26946. const components = [];
  26947. const shouldRenderHelp = useHelpAccessibility(editor);
  26948. const shouldRenderElementPath = useElementPath(editor);
  26949. const shouldRenderRightContainer = useBranding(editor) || editor.hasPlugin('wordcount');
  26950. const getTextComponentClasses = () => {
  26951. const flexStart = 'tox-statusbar__text-container--flex-start';
  26952. const flexEnd = 'tox-statusbar__text-container--flex-end';
  26953. const spaceAround = 'tox-statusbar__text-container--space-around';
  26954. if (shouldRenderHelp) {
  26955. const container3Columns = 'tox-statusbar__text-container-3-cols';
  26956. if (!shouldRenderRightContainer && !shouldRenderElementPath) {
  26957. return [
  26958. container3Columns,
  26959. spaceAround
  26960. ];
  26961. }
  26962. if (shouldRenderRightContainer && !shouldRenderElementPath) {
  26963. return [
  26964. container3Columns,
  26965. flexEnd
  26966. ];
  26967. }
  26968. return [
  26969. container3Columns,
  26970. flexStart
  26971. ];
  26972. }
  26973. return [shouldRenderRightContainer && !shouldRenderElementPath ? flexEnd : flexStart];
  26974. };
  26975. if (shouldRenderElementPath) {
  26976. components.push(renderElementPath(editor, {}, providersBackstage));
  26977. }
  26978. if (shouldRenderHelp) {
  26979. components.push(renderHelpAccessibility());
  26980. }
  26981. if (shouldRenderRightContainer) {
  26982. components.push(renderRightContainer());
  26983. }
  26984. if (components.length > 0) {
  26985. return [{
  26986. dom: {
  26987. tag: 'div',
  26988. classes: [
  26989. 'tox-statusbar__text-container',
  26990. ...getTextComponentClasses()
  26991. ]
  26992. },
  26993. components
  26994. }];
  26995. }
  26996. return [];
  26997. };
  26998. const getComponents = () => {
  26999. const components = getTextComponents();
  27000. const resizeHandler = renderResizeHandler(editor, providersBackstage);
  27001. return components.concat(resizeHandler.toArray());
  27002. };
  27003. return {
  27004. dom: {
  27005. tag: 'div',
  27006. classes: ['tox-statusbar']
  27007. },
  27008. components: getComponents()
  27009. };
  27010. };
  27011. const getLazyMothership = (label, singleton) => singleton.get().getOrDie(`UI for ${ label } has not been rendered`);
  27012. const setup$3 = (editor, setupForTheme) => {
  27013. const isInline = editor.inline;
  27014. const mode = isInline ? Inline : Iframe;
  27015. const header = isStickyToolbar(editor) ? StickyHeader : StaticHeader;
  27016. const lazyUiRefs = LazyUiReferences();
  27017. const lazyMothership = value$2();
  27018. const lazyDialogMothership = value$2();
  27019. const lazyPopupMothership = value$2();
  27020. const platform = detect$2();
  27021. const isTouch = platform.deviceType.isTouch();
  27022. const touchPlatformClass = 'tox-platform-touch';
  27023. const deviceClasses = isTouch ? [touchPlatformClass] : [];
  27024. const isToolbarBottom = isToolbarLocationBottom(editor);
  27025. const toolbarMode = getToolbarMode(editor);
  27026. const memAnchorBar = record({
  27027. dom: {
  27028. tag: 'div',
  27029. classes: ['tox-anchorbar']
  27030. }
  27031. });
  27032. const memBottomAnchorBar = record({
  27033. dom: {
  27034. tag: 'div',
  27035. classes: ['tox-bottom-anchorbar']
  27036. }
  27037. });
  27038. const lazyHeader = () => lazyUiRefs.mainUi.get().map(ui => ui.outerContainer).bind(OuterContainer.getHeader);
  27039. const lazyDialogSinkResult = () => Result.fromOption(lazyUiRefs.dialogUi.get().map(ui => ui.sink), 'UI has not been rendered');
  27040. const lazyPopupSinkResult = () => Result.fromOption(lazyUiRefs.popupUi.get().map(ui => ui.sink), '(popup) UI has not been rendered');
  27041. const lazyAnchorBar = lazyUiRefs.lazyGetInOuterOrDie('anchor bar', memAnchorBar.getOpt);
  27042. const lazyBottomAnchorBar = lazyUiRefs.lazyGetInOuterOrDie('bottom anchor bar', memBottomAnchorBar.getOpt);
  27043. const lazyToolbar = lazyUiRefs.lazyGetInOuterOrDie('toolbar', OuterContainer.getToolbar);
  27044. const lazyThrobber = lazyUiRefs.lazyGetInOuterOrDie('throbber', OuterContainer.getThrobber);
  27045. const backstages = init$6({
  27046. popup: lazyPopupSinkResult,
  27047. dialog: lazyDialogSinkResult
  27048. }, editor, lazyAnchorBar, lazyBottomAnchorBar);
  27049. const makeHeaderPart = () => {
  27050. const verticalDirAttributes = { attributes: { [Attribute]: isToolbarBottom ? AttributeValue.BottomToTop : AttributeValue.TopToBottom } };
  27051. const partMenubar = OuterContainer.parts.menubar({
  27052. dom: {
  27053. tag: 'div',
  27054. classes: ['tox-menubar']
  27055. },
  27056. backstage: backstages.popup,
  27057. onEscape: () => {
  27058. editor.focus();
  27059. }
  27060. });
  27061. const partToolbar = OuterContainer.parts.toolbar({
  27062. dom: {
  27063. tag: 'div',
  27064. classes: ['tox-toolbar']
  27065. },
  27066. getSink: backstages.popup.shared.getSink,
  27067. providers: backstages.popup.shared.providers,
  27068. onEscape: () => {
  27069. editor.focus();
  27070. },
  27071. onToolbarToggled: state => {
  27072. fireToggleToolbarDrawer(editor, state);
  27073. },
  27074. type: toolbarMode,
  27075. lazyToolbar,
  27076. lazyHeader: () => lazyHeader().getOrDie('Could not find header element'),
  27077. ...verticalDirAttributes
  27078. });
  27079. const partMultipleToolbar = OuterContainer.parts['multiple-toolbar']({
  27080. dom: {
  27081. tag: 'div',
  27082. classes: ['tox-toolbar-overlord']
  27083. },
  27084. providers: backstages.popup.shared.providers,
  27085. onEscape: () => {
  27086. editor.focus();
  27087. },
  27088. type: toolbarMode
  27089. });
  27090. const hasMultipleToolbar = isMultipleToolbars(editor);
  27091. const hasToolbar = isToolbarEnabled(editor);
  27092. const hasMenubar = isMenubarEnabled(editor);
  27093. const shouldHavePromotion = promotionEnabled(editor);
  27094. const partPromotion = makePromotion();
  27095. const hasAnyContents = hasMultipleToolbar || hasToolbar || hasMenubar;
  27096. const getPartToolbar = () => {
  27097. if (hasMultipleToolbar) {
  27098. return [partMultipleToolbar];
  27099. } else if (hasToolbar) {
  27100. return [partToolbar];
  27101. } else {
  27102. return [];
  27103. }
  27104. };
  27105. const menubarCollection = shouldHavePromotion ? [
  27106. partPromotion,
  27107. partMenubar
  27108. ] : [partMenubar];
  27109. return OuterContainer.parts.header({
  27110. dom: {
  27111. tag: 'div',
  27112. classes: ['tox-editor-header'].concat(hasAnyContents ? [] : ['tox-editor-header--empty']),
  27113. ...verticalDirAttributes
  27114. },
  27115. components: flatten([
  27116. hasMenubar ? menubarCollection : [],
  27117. getPartToolbar(),
  27118. useFixedContainer(editor) ? [] : [memAnchorBar.asSpec()]
  27119. ]),
  27120. sticky: isStickyToolbar(editor),
  27121. editor,
  27122. sharedBackstage: backstages.popup.shared
  27123. });
  27124. };
  27125. const makePromotion = () => {
  27126. return OuterContainer.parts.promotion({
  27127. dom: {
  27128. tag: 'div',
  27129. classes: ['tox-promotion']
  27130. }
  27131. });
  27132. };
  27133. const makeSidebarDefinition = () => {
  27134. const partSocket = OuterContainer.parts.socket({
  27135. dom: {
  27136. tag: 'div',
  27137. classes: ['tox-edit-area']
  27138. }
  27139. });
  27140. const partSidebar = OuterContainer.parts.sidebar({
  27141. dom: {
  27142. tag: 'div',
  27143. classes: ['tox-sidebar']
  27144. }
  27145. });
  27146. return {
  27147. dom: {
  27148. tag: 'div',
  27149. classes: ['tox-sidebar-wrap']
  27150. },
  27151. components: [
  27152. partSocket,
  27153. partSidebar
  27154. ]
  27155. };
  27156. };
  27157. const renderDialogUi = () => {
  27158. const uiContainer = getUiContainer(editor);
  27159. const isGridUiContainer = eq(body(), uiContainer) && get$e(uiContainer, 'display') === 'grid';
  27160. const sinkSpec = {
  27161. dom: {
  27162. tag: 'div',
  27163. classes: [
  27164. 'tox',
  27165. 'tox-silver-sink',
  27166. 'tox-tinymce-aux'
  27167. ].concat(deviceClasses),
  27168. attributes: { ...global$8.isRtl() ? { dir: 'rtl' } : {} }
  27169. },
  27170. behaviours: derive$1([Positioning.config({ useFixed: () => header.isDocked(lazyHeader) })])
  27171. };
  27172. const reactiveWidthSpec = {
  27173. dom: { styles: { width: document.body.clientWidth + 'px' } },
  27174. events: derive$2([run$1(windowResize(), comp => {
  27175. set$8(comp.element, 'width', document.body.clientWidth + 'px');
  27176. })])
  27177. };
  27178. const sink = build$1(deepMerge(sinkSpec, isGridUiContainer ? reactiveWidthSpec : {}));
  27179. const uiMothership = takeover(sink);
  27180. lazyDialogMothership.set(uiMothership);
  27181. return {
  27182. sink,
  27183. mothership: uiMothership
  27184. };
  27185. };
  27186. const renderPopupUi = () => {
  27187. const sinkSpec = {
  27188. dom: {
  27189. tag: 'div',
  27190. classes: [
  27191. 'tox',
  27192. 'tox-silver-sink',
  27193. 'tox-silver-popup-sink',
  27194. 'tox-tinymce-aux'
  27195. ].concat(deviceClasses),
  27196. attributes: { ...global$8.isRtl() ? { dir: 'rtl' } : {} }
  27197. },
  27198. behaviours: derive$1([Positioning.config({
  27199. useFixed: () => header.isDocked(lazyHeader),
  27200. getBounds: () => setupForTheme.getPopupSinkBounds()
  27201. })])
  27202. };
  27203. const sink = build$1(sinkSpec);
  27204. const uiMothership = takeover(sink);
  27205. lazyPopupMothership.set(uiMothership);
  27206. return {
  27207. sink,
  27208. mothership: uiMothership
  27209. };
  27210. };
  27211. const renderMainUi = () => {
  27212. const partHeader = makeHeaderPart();
  27213. const sidebarContainer = makeSidebarDefinition();
  27214. const partThrobber = OuterContainer.parts.throbber({
  27215. dom: {
  27216. tag: 'div',
  27217. classes: ['tox-throbber']
  27218. },
  27219. backstage: backstages.popup
  27220. });
  27221. const partViewWrapper = OuterContainer.parts.viewWrapper({ backstage: backstages.popup });
  27222. const statusbar = useStatusBar(editor) && !isInline ? Optional.some(renderStatusbar(editor, backstages.popup.shared.providers)) : Optional.none();
  27223. const editorComponents = flatten([
  27224. isToolbarBottom ? [] : [partHeader],
  27225. isInline ? [] : [sidebarContainer],
  27226. isToolbarBottom ? [partHeader] : []
  27227. ]);
  27228. const editorContainer = OuterContainer.parts.editorContainer({
  27229. components: flatten([
  27230. editorComponents,
  27231. isInline ? [] : [
  27232. memBottomAnchorBar.asSpec(),
  27233. ...statusbar.toArray()
  27234. ]
  27235. ])
  27236. });
  27237. const isHidden = isDistractionFree(editor);
  27238. const attributes = {
  27239. role: 'application',
  27240. ...global$8.isRtl() ? { dir: 'rtl' } : {},
  27241. ...isHidden ? { 'aria-hidden': 'true' } : {}
  27242. };
  27243. const outerContainer = build$1(OuterContainer.sketch({
  27244. dom: {
  27245. tag: 'div',
  27246. classes: [
  27247. 'tox',
  27248. 'tox-tinymce'
  27249. ].concat(isInline ? ['tox-tinymce-inline'] : []).concat(isToolbarBottom ? ['tox-tinymce--toolbar-bottom'] : []).concat(deviceClasses),
  27250. styles: {
  27251. visibility: 'hidden',
  27252. ...isHidden ? {
  27253. opacity: '0',
  27254. border: '0'
  27255. } : {}
  27256. },
  27257. attributes
  27258. },
  27259. components: [
  27260. editorContainer,
  27261. ...isInline ? [] : [partViewWrapper],
  27262. partThrobber
  27263. ],
  27264. behaviours: derive$1([
  27265. receivingConfig(),
  27266. Disabling.config({ disableClass: 'tox-tinymce--disabled' }),
  27267. Keying.config({
  27268. mode: 'cyclic',
  27269. selector: '.tox-menubar, .tox-toolbar, .tox-toolbar__primary, .tox-toolbar__overflow--open, .tox-sidebar__overflow--open, .tox-statusbar__path, .tox-statusbar__wordcount, .tox-statusbar__branding a, .tox-statusbar__resize-handle'
  27270. })
  27271. ])
  27272. }));
  27273. const mothership = takeover(outerContainer);
  27274. lazyMothership.set(mothership);
  27275. return {
  27276. mothership,
  27277. outerContainer
  27278. };
  27279. };
  27280. const setEditorSize = outerContainer => {
  27281. const parsedHeight = numToPx(getHeightWithFallback(editor));
  27282. const parsedWidth = numToPx(getWidthWithFallback(editor));
  27283. if (!editor.inline) {
  27284. if (isValidValue$1('div', 'width', parsedWidth)) {
  27285. set$8(outerContainer.element, 'width', parsedWidth);
  27286. }
  27287. if (isValidValue$1('div', 'height', parsedHeight)) {
  27288. set$8(outerContainer.element, 'height', parsedHeight);
  27289. } else {
  27290. set$8(outerContainer.element, 'height', '400px');
  27291. }
  27292. }
  27293. return parsedHeight;
  27294. };
  27295. const setupShortcutsAndCommands = outerContainer => {
  27296. editor.addShortcut('alt+F9', 'focus menubar', () => {
  27297. OuterContainer.focusMenubar(outerContainer);
  27298. });
  27299. editor.addShortcut('alt+F10', 'focus toolbar', () => {
  27300. OuterContainer.focusToolbar(outerContainer);
  27301. });
  27302. editor.addCommand('ToggleToolbarDrawer', (_ui, options) => {
  27303. if (options === null || options === void 0 ? void 0 : options.skipFocus) {
  27304. OuterContainer.toggleToolbarDrawerWithoutFocusing(outerContainer);
  27305. } else {
  27306. OuterContainer.toggleToolbarDrawer(outerContainer);
  27307. }
  27308. });
  27309. editor.addQueryStateHandler('ToggleToolbarDrawer', () => OuterContainer.isToolbarDrawerToggled(outerContainer));
  27310. };
  27311. const renderUIWithRefs = uiRefs => {
  27312. const {mainUi, popupUi, uiMotherships} = uiRefs;
  27313. map$1(getToolbarGroups(editor), (toolbarGroupButtonConfig, name) => {
  27314. editor.ui.registry.addGroupToolbarButton(name, toolbarGroupButtonConfig);
  27315. });
  27316. const {buttons, menuItems, contextToolbars, sidebars, views} = editor.ui.registry.getAll();
  27317. const toolbarOpt = getMultipleToolbarsOption(editor);
  27318. const rawUiConfig = {
  27319. menuItems,
  27320. menus: getMenus(editor),
  27321. menubar: getMenubar(editor),
  27322. toolbar: toolbarOpt.getOrThunk(() => getToolbar(editor)),
  27323. allowToolbarGroups: toolbarMode === ToolbarMode$1.floating,
  27324. buttons,
  27325. sidebar: sidebars,
  27326. views
  27327. };
  27328. setupShortcutsAndCommands(mainUi.outerContainer);
  27329. setup$b(editor, mainUi.mothership, uiMotherships);
  27330. header.setup(editor, backstages.popup.shared, lazyHeader);
  27331. setup$6(editor, backstages.popup);
  27332. setup$5(editor, backstages.popup.shared.getSink, backstages.popup);
  27333. setup$8(editor);
  27334. setup$7(editor, lazyThrobber, backstages.popup.shared);
  27335. register$9(editor, contextToolbars, popupUi.sink, { backstage: backstages.popup });
  27336. setup$4(editor, popupUi.sink);
  27337. const elm = editor.getElement();
  27338. const height = setEditorSize(mainUi.outerContainer);
  27339. const args = {
  27340. targetNode: elm,
  27341. height
  27342. };
  27343. return mode.render(editor, uiRefs, rawUiConfig, backstages.popup, args);
  27344. };
  27345. const reuseDialogUiForPopuUi = dialogUi => {
  27346. lazyPopupMothership.set(dialogUi.mothership);
  27347. return dialogUi;
  27348. };
  27349. const renderUI = () => {
  27350. const mainUi = renderMainUi();
  27351. const dialogUi = renderDialogUi();
  27352. const popupUi = isSplitUiMode(editor) ? renderPopupUi() : reuseDialogUiForPopuUi(dialogUi);
  27353. lazyUiRefs.dialogUi.set(dialogUi);
  27354. lazyUiRefs.popupUi.set(popupUi);
  27355. lazyUiRefs.mainUi.set(mainUi);
  27356. const uiRefs = {
  27357. popupUi,
  27358. dialogUi,
  27359. mainUi,
  27360. uiMotherships: lazyUiRefs.getUiMotherships()
  27361. };
  27362. return renderUIWithRefs(uiRefs);
  27363. };
  27364. return {
  27365. popups: {
  27366. backstage: backstages.popup,
  27367. getMothership: () => getLazyMothership('popups', lazyPopupMothership)
  27368. },
  27369. dialogs: {
  27370. backstage: backstages.dialog,
  27371. getMothership: () => getLazyMothership('dialogs', lazyDialogMothership)
  27372. },
  27373. renderUI
  27374. };
  27375. };
  27376. const labelledBy = (labelledElement, labelElement) => {
  27377. const labelId = getOpt(labelledElement, 'id').fold(() => {
  27378. const id = generate$6('dialog-label');
  27379. set$9(labelElement, 'id', id);
  27380. return id;
  27381. }, identity);
  27382. set$9(labelledElement, 'aria-labelledby', labelId);
  27383. };
  27384. const schema$2 = constant$1([
  27385. required$1('lazySink'),
  27386. option$3('dragBlockClass'),
  27387. defaultedFunction('getBounds', win),
  27388. defaulted('useTabstopAt', always),
  27389. defaulted('firstTabstop', 0),
  27390. defaulted('eventOrder', {}),
  27391. field('modalBehaviours', [Keying]),
  27392. onKeyboardHandler('onExecute'),
  27393. onStrictKeyboardHandler('onEscape')
  27394. ]);
  27395. const basic = { sketch: identity };
  27396. const parts$2 = constant$1([
  27397. optional({
  27398. name: 'draghandle',
  27399. overrides: (detail, spec) => {
  27400. return {
  27401. behaviours: derive$1([Dragging.config({
  27402. mode: 'mouse',
  27403. getTarget: handle => {
  27404. return ancestor(handle, '[role="dialog"]').getOr(handle);
  27405. },
  27406. blockerClass: detail.dragBlockClass.getOrDie(new Error('The drag blocker class was not specified for a dialog with a drag handle: \n' + JSON.stringify(spec, null, 2)).message),
  27407. getBounds: detail.getDragBounds
  27408. })])
  27409. };
  27410. }
  27411. }),
  27412. required({
  27413. schema: [required$1('dom')],
  27414. name: 'title'
  27415. }),
  27416. required({
  27417. factory: basic,
  27418. schema: [required$1('dom')],
  27419. name: 'close'
  27420. }),
  27421. required({
  27422. factory: basic,
  27423. schema: [required$1('dom')],
  27424. name: 'body'
  27425. }),
  27426. optional({
  27427. factory: basic,
  27428. schema: [required$1('dom')],
  27429. name: 'footer'
  27430. }),
  27431. external({
  27432. factory: {
  27433. sketch: (spec, detail) => ({
  27434. ...spec,
  27435. dom: detail.dom,
  27436. components: detail.components
  27437. })
  27438. },
  27439. schema: [
  27440. defaulted('dom', {
  27441. tag: 'div',
  27442. styles: {
  27443. position: 'fixed',
  27444. left: '0px',
  27445. top: '0px',
  27446. right: '0px',
  27447. bottom: '0px'
  27448. }
  27449. }),
  27450. defaulted('components', [])
  27451. ],
  27452. name: 'blocker'
  27453. })
  27454. ]);
  27455. const factory$4 = (detail, components, spec, externals) => {
  27456. const dialogComp = value$2();
  27457. const showDialog = dialog => {
  27458. dialogComp.set(dialog);
  27459. const sink = detail.lazySink(dialog).getOrDie();
  27460. const externalBlocker = externals.blocker();
  27461. const blocker = sink.getSystem().build({
  27462. ...externalBlocker,
  27463. components: externalBlocker.components.concat([premade(dialog)]),
  27464. behaviours: derive$1([
  27465. Focusing.config({}),
  27466. config('dialog-blocker-events', [runOnSource(focusin(), () => {
  27467. Blocking.isBlocked(dialog) ? noop() : Keying.focusIn(dialog);
  27468. })])
  27469. ])
  27470. });
  27471. attach(sink, blocker);
  27472. Keying.focusIn(dialog);
  27473. };
  27474. const hideDialog = dialog => {
  27475. dialogComp.clear();
  27476. parent(dialog.element).each(blockerDom => {
  27477. dialog.getSystem().getByDom(blockerDom).each(blocker => {
  27478. detach(blocker);
  27479. });
  27480. });
  27481. };
  27482. const getDialogBody = dialog => getPartOrDie(dialog, detail, 'body');
  27483. const getDialogFooter = dialog => getPart(dialog, detail, 'footer');
  27484. const setBusy = (dialog, getBusySpec) => {
  27485. Blocking.block(dialog, getBusySpec);
  27486. };
  27487. const setIdle = dialog => {
  27488. Blocking.unblock(dialog);
  27489. };
  27490. const modalEventsId = generate$6('modal-events');
  27491. const eventOrder = {
  27492. ...detail.eventOrder,
  27493. [attachedToDom()]: [modalEventsId].concat(detail.eventOrder['alloy.system.attached'] || [])
  27494. };
  27495. return {
  27496. uid: detail.uid,
  27497. dom: detail.dom,
  27498. components,
  27499. apis: {
  27500. show: showDialog,
  27501. hide: hideDialog,
  27502. getBody: getDialogBody,
  27503. getFooter: getDialogFooter,
  27504. setIdle,
  27505. setBusy
  27506. },
  27507. eventOrder,
  27508. domModification: {
  27509. attributes: {
  27510. 'role': 'dialog',
  27511. 'aria-modal': 'true'
  27512. }
  27513. },
  27514. behaviours: augment(detail.modalBehaviours, [
  27515. Replacing.config({}),
  27516. Keying.config({
  27517. mode: 'cyclic',
  27518. onEnter: detail.onExecute,
  27519. onEscape: detail.onEscape,
  27520. useTabstopAt: detail.useTabstopAt,
  27521. firstTabstop: detail.firstTabstop
  27522. }),
  27523. Blocking.config({ getRoot: dialogComp.get }),
  27524. config(modalEventsId, [runOnAttached(c => {
  27525. labelledBy(c.element, getPartOrDie(c, detail, 'title').element);
  27526. })])
  27527. ])
  27528. };
  27529. };
  27530. const ModalDialog = composite({
  27531. name: 'ModalDialog',
  27532. configFields: schema$2(),
  27533. partFields: parts$2(),
  27534. factory: factory$4,
  27535. apis: {
  27536. show: (apis, dialog) => {
  27537. apis.show(dialog);
  27538. },
  27539. hide: (apis, dialog) => {
  27540. apis.hide(dialog);
  27541. },
  27542. getBody: (apis, dialog) => apis.getBody(dialog),
  27543. getFooter: (apis, dialog) => apis.getFooter(dialog),
  27544. setBusy: (apis, dialog, getBusySpec) => {
  27545. apis.setBusy(dialog, getBusySpec);
  27546. },
  27547. setIdle: (apis, dialog) => {
  27548. apis.setIdle(dialog);
  27549. }
  27550. }
  27551. });
  27552. const dialogToggleMenuItemSchema = objOf([
  27553. type,
  27554. name$1
  27555. ].concat(commonMenuItemFields));
  27556. const dialogToggleMenuItemDataProcessor = boolean;
  27557. const baseFooterButtonFields = [
  27558. generatedName('button'),
  27559. optionalIcon,
  27560. defaultedStringEnum('align', 'end', [
  27561. 'start',
  27562. 'end'
  27563. ]),
  27564. primary,
  27565. enabled,
  27566. optionStringEnum('buttonType', [
  27567. 'primary',
  27568. 'secondary'
  27569. ])
  27570. ];
  27571. const dialogFooterButtonFields = [
  27572. ...baseFooterButtonFields,
  27573. text
  27574. ];
  27575. const normalFooterButtonFields = [
  27576. requiredStringEnum('type', [
  27577. 'submit',
  27578. 'cancel',
  27579. 'custom'
  27580. ]),
  27581. ...dialogFooterButtonFields
  27582. ];
  27583. const menuFooterButtonFields = [
  27584. requiredStringEnum('type', ['menu']),
  27585. optionalText,
  27586. optionalTooltip,
  27587. optionalIcon,
  27588. requiredArrayOf('items', dialogToggleMenuItemSchema),
  27589. ...baseFooterButtonFields
  27590. ];
  27591. const toggleButtonSpecFields = [
  27592. ...baseFooterButtonFields,
  27593. requiredStringEnum('type', ['togglebutton']),
  27594. requiredString('tooltip'),
  27595. optionalIcon,
  27596. optionalText,
  27597. defaultedBoolean('active', false)
  27598. ];
  27599. const dialogFooterButtonSchema = choose$1('type', {
  27600. submit: normalFooterButtonFields,
  27601. cancel: normalFooterButtonFields,
  27602. custom: normalFooterButtonFields,
  27603. menu: menuFooterButtonFields,
  27604. togglebutton: toggleButtonSpecFields
  27605. });
  27606. const alertBannerFields = [
  27607. type,
  27608. text,
  27609. requiredStringEnum('level', [
  27610. 'info',
  27611. 'warn',
  27612. 'error',
  27613. 'success'
  27614. ]),
  27615. icon,
  27616. defaulted('url', '')
  27617. ];
  27618. const alertBannerSchema = objOf(alertBannerFields);
  27619. const createBarFields = itemsField => [
  27620. type,
  27621. itemsField
  27622. ];
  27623. const buttonFields = [
  27624. type,
  27625. text,
  27626. enabled,
  27627. generatedName('button'),
  27628. optionalIcon,
  27629. borderless,
  27630. optionStringEnum('buttonType', [
  27631. 'primary',
  27632. 'secondary',
  27633. 'toolbar'
  27634. ]),
  27635. primary
  27636. ];
  27637. const buttonSchema = objOf(buttonFields);
  27638. const formComponentFields = [
  27639. type,
  27640. name$1
  27641. ];
  27642. const formComponentWithLabelFields = formComponentFields.concat([optionalLabel]);
  27643. const checkboxFields = formComponentFields.concat([
  27644. label,
  27645. enabled
  27646. ]);
  27647. const checkboxSchema = objOf(checkboxFields);
  27648. const checkboxDataProcessor = boolean;
  27649. const collectionFields = formComponentWithLabelFields.concat([defaultedColumns('auto')]);
  27650. const collectionSchema = objOf(collectionFields);
  27651. const collectionDataProcessor = arrOfObj([
  27652. value$1,
  27653. text,
  27654. icon
  27655. ]);
  27656. const colorInputFields = formComponentWithLabelFields.concat([defaultedString('storageKey', 'default')]);
  27657. const colorInputSchema = objOf(colorInputFields);
  27658. const colorInputDataProcessor = string;
  27659. const colorPickerFields = formComponentWithLabelFields;
  27660. const colorPickerSchema = objOf(colorPickerFields);
  27661. const colorPickerDataProcessor = string;
  27662. const customEditorFields = formComponentFields.concat([
  27663. defaultedString('tag', 'textarea'),
  27664. requiredString('scriptId'),
  27665. requiredString('scriptUrl'),
  27666. defaultedPostMsg('settings', undefined)
  27667. ]);
  27668. const customEditorFieldsOld = formComponentFields.concat([
  27669. defaultedString('tag', 'textarea'),
  27670. requiredFunction('init')
  27671. ]);
  27672. const customEditorSchema = valueOf(v => asRaw('customeditor.old', objOfOnly(customEditorFieldsOld), v).orThunk(() => asRaw('customeditor.new', objOfOnly(customEditorFields), v)));
  27673. const customEditorDataProcessor = string;
  27674. const dropZoneFields = formComponentWithLabelFields;
  27675. const dropZoneSchema = objOf(dropZoneFields);
  27676. const dropZoneDataProcessor = arrOfVal();
  27677. const createGridFields = itemsField => [
  27678. type,
  27679. requiredNumber('columns'),
  27680. itemsField
  27681. ];
  27682. const htmlPanelFields = [
  27683. type,
  27684. requiredString('html'),
  27685. defaultedStringEnum('presets', 'presentation', [
  27686. 'presentation',
  27687. 'document'
  27688. ])
  27689. ];
  27690. const htmlPanelSchema = objOf(htmlPanelFields);
  27691. const iframeFields = formComponentWithLabelFields.concat([
  27692. defaultedBoolean('border', false),
  27693. defaultedBoolean('sandboxed', true),
  27694. defaultedBoolean('streamContent', false),
  27695. defaultedBoolean('transparent', true)
  27696. ]);
  27697. const iframeSchema = objOf(iframeFields);
  27698. const iframeDataProcessor = string;
  27699. const imagePreviewSchema = objOf(formComponentFields.concat([optionString('height')]));
  27700. const imagePreviewDataProcessor = objOf([
  27701. requiredString('url'),
  27702. optionNumber('zoom'),
  27703. optionNumber('cachedWidth'),
  27704. optionNumber('cachedHeight')
  27705. ]);
  27706. const inputFields = formComponentWithLabelFields.concat([
  27707. optionString('inputMode'),
  27708. optionString('placeholder'),
  27709. defaultedBoolean('maximized', false),
  27710. enabled
  27711. ]);
  27712. const inputSchema = objOf(inputFields);
  27713. const inputDataProcessor = string;
  27714. const createLabelFields = itemsField => [
  27715. type,
  27716. label,
  27717. itemsField,
  27718. defaultedStringEnum('align', 'start', [
  27719. 'start',
  27720. 'center',
  27721. 'end'
  27722. ])
  27723. ];
  27724. const listBoxSingleItemFields = [
  27725. text,
  27726. value$1
  27727. ];
  27728. const listBoxNestedItemFields = [
  27729. text,
  27730. requiredArrayOf('items', thunkOf('items', () => listBoxItemSchema))
  27731. ];
  27732. const listBoxItemSchema = oneOf([
  27733. objOf(listBoxSingleItemFields),
  27734. objOf(listBoxNestedItemFields)
  27735. ]);
  27736. const listBoxFields = formComponentWithLabelFields.concat([
  27737. requiredArrayOf('items', listBoxItemSchema),
  27738. enabled
  27739. ]);
  27740. const listBoxSchema = objOf(listBoxFields);
  27741. const listBoxDataProcessor = string;
  27742. const selectBoxFields = formComponentWithLabelFields.concat([
  27743. requiredArrayOfObj('items', [
  27744. text,
  27745. value$1
  27746. ]),
  27747. defaultedNumber('size', 1),
  27748. enabled
  27749. ]);
  27750. const selectBoxSchema = objOf(selectBoxFields);
  27751. const selectBoxDataProcessor = string;
  27752. const sizeInputFields = formComponentWithLabelFields.concat([
  27753. defaultedBoolean('constrain', true),
  27754. enabled
  27755. ]);
  27756. const sizeInputSchema = objOf(sizeInputFields);
  27757. const sizeInputDataProcessor = objOf([
  27758. requiredString('width'),
  27759. requiredString('height')
  27760. ]);
  27761. const sliderFields = formComponentFields.concat([
  27762. label,
  27763. defaultedNumber('min', 0),
  27764. defaultedNumber('max', 0)
  27765. ]);
  27766. const sliderSchema = objOf(sliderFields);
  27767. const sliderInputDataProcessor = number;
  27768. const tableFields = [
  27769. type,
  27770. requiredArrayOf('header', string),
  27771. requiredArrayOf('cells', arrOf(string))
  27772. ];
  27773. const tableSchema = objOf(tableFields);
  27774. const textAreaFields = formComponentWithLabelFields.concat([
  27775. optionString('placeholder'),
  27776. defaultedBoolean('maximized', false),
  27777. enabled
  27778. ]);
  27779. const textAreaSchema = objOf(textAreaFields);
  27780. const textAreaDataProcessor = string;
  27781. const baseTreeItemFields = [
  27782. requiredStringEnum('type', [
  27783. 'directory',
  27784. 'leaf'
  27785. ]),
  27786. title,
  27787. requiredString('id'),
  27788. optionOf('menu', MenuButtonSchema)
  27789. ];
  27790. const treeItemLeafFields = baseTreeItemFields;
  27791. const treeItemLeafSchema = objOf(treeItemLeafFields);
  27792. const treeItemDirectoryFields = baseTreeItemFields.concat([requiredArrayOf('children', thunkOf('children', () => {
  27793. return choose$2('type', {
  27794. directory: treeItemDirectorySchema,
  27795. leaf: treeItemLeafSchema
  27796. });
  27797. }))]);
  27798. const treeItemDirectorySchema = objOf(treeItemDirectoryFields);
  27799. const treeItemSchema = choose$2('type', {
  27800. directory: treeItemDirectorySchema,
  27801. leaf: treeItemLeafSchema
  27802. });
  27803. const treeFields = [
  27804. type,
  27805. requiredArrayOf('items', treeItemSchema),
  27806. optionFunction('onLeafAction'),
  27807. optionFunction('onToggleExpand'),
  27808. defaultedArrayOf('defaultExpandedIds', [], string),
  27809. optionString('defaultSelectedId')
  27810. ];
  27811. const treeSchema = objOf(treeFields);
  27812. const urlInputFields = formComponentWithLabelFields.concat([
  27813. defaultedStringEnum('filetype', 'file', [
  27814. 'image',
  27815. 'media',
  27816. 'file'
  27817. ]),
  27818. enabled,
  27819. optionString('picker_text')
  27820. ]);
  27821. const urlInputSchema = objOf(urlInputFields);
  27822. const urlInputDataProcessor = objOf([
  27823. value$1,
  27824. defaultedMeta
  27825. ]);
  27826. const createItemsField = name => field$1('items', 'items', required$2(), arrOf(valueOf(v => asRaw(`Checking item of ${ name }`, itemSchema, v).fold(sErr => Result.error(formatError(sErr)), passValue => Result.value(passValue)))));
  27827. const itemSchema = valueThunk(() => choose$2('type', {
  27828. alertbanner: alertBannerSchema,
  27829. bar: objOf(createBarFields(createItemsField('bar'))),
  27830. button: buttonSchema,
  27831. checkbox: checkboxSchema,
  27832. colorinput: colorInputSchema,
  27833. colorpicker: colorPickerSchema,
  27834. dropzone: dropZoneSchema,
  27835. grid: objOf(createGridFields(createItemsField('grid'))),
  27836. iframe: iframeSchema,
  27837. input: inputSchema,
  27838. listbox: listBoxSchema,
  27839. selectbox: selectBoxSchema,
  27840. sizeinput: sizeInputSchema,
  27841. slider: sliderSchema,
  27842. textarea: textAreaSchema,
  27843. urlinput: urlInputSchema,
  27844. customeditor: customEditorSchema,
  27845. htmlpanel: htmlPanelSchema,
  27846. imagepreview: imagePreviewSchema,
  27847. collection: collectionSchema,
  27848. label: objOf(createLabelFields(createItemsField('label'))),
  27849. table: tableSchema,
  27850. tree: treeSchema,
  27851. panel: panelSchema
  27852. }));
  27853. const panelFields = [
  27854. type,
  27855. defaulted('classes', []),
  27856. requiredArrayOf('items', itemSchema)
  27857. ];
  27858. const panelSchema = objOf(panelFields);
  27859. const tabFields = [
  27860. generatedName('tab'),
  27861. title,
  27862. requiredArrayOf('items', itemSchema)
  27863. ];
  27864. const tabPanelFields = [
  27865. type,
  27866. requiredArrayOfObj('tabs', tabFields)
  27867. ];
  27868. const tabPanelSchema = objOf(tabPanelFields);
  27869. const dialogButtonFields = dialogFooterButtonFields;
  27870. const dialogButtonSchema = dialogFooterButtonSchema;
  27871. const dialogSchema = objOf([
  27872. requiredString('title'),
  27873. requiredOf('body', choose$2('type', {
  27874. panel: panelSchema,
  27875. tabpanel: tabPanelSchema
  27876. })),
  27877. defaultedString('size', 'normal'),
  27878. defaultedArrayOf('buttons', [], dialogButtonSchema),
  27879. defaulted('initialData', {}),
  27880. defaultedFunction('onAction', noop),
  27881. defaultedFunction('onChange', noop),
  27882. defaultedFunction('onSubmit', noop),
  27883. defaultedFunction('onClose', noop),
  27884. defaultedFunction('onCancel', noop),
  27885. defaultedFunction('onTabChange', noop)
  27886. ]);
  27887. const createDialog = spec => asRaw('dialog', dialogSchema, spec);
  27888. const urlDialogButtonSchema = objOf([
  27889. requiredStringEnum('type', [
  27890. 'cancel',
  27891. 'custom'
  27892. ]),
  27893. ...dialogButtonFields
  27894. ]);
  27895. const urlDialogSchema = objOf([
  27896. requiredString('title'),
  27897. requiredString('url'),
  27898. optionNumber('height'),
  27899. optionNumber('width'),
  27900. optionArrayOf('buttons', urlDialogButtonSchema),
  27901. defaultedFunction('onAction', noop),
  27902. defaultedFunction('onCancel', noop),
  27903. defaultedFunction('onClose', noop),
  27904. defaultedFunction('onMessage', noop)
  27905. ]);
  27906. const createUrlDialog = spec => asRaw('dialog', urlDialogSchema, spec);
  27907. const getAllObjects = obj => {
  27908. if (isObject(obj)) {
  27909. return [obj].concat(bind$3(values(obj), getAllObjects));
  27910. } else if (isArray(obj)) {
  27911. return bind$3(obj, getAllObjects);
  27912. } else {
  27913. return [];
  27914. }
  27915. };
  27916. const isNamedItem = obj => isString(obj.type) && isString(obj.name);
  27917. const dataProcessors = {
  27918. checkbox: checkboxDataProcessor,
  27919. colorinput: colorInputDataProcessor,
  27920. colorpicker: colorPickerDataProcessor,
  27921. dropzone: dropZoneDataProcessor,
  27922. input: inputDataProcessor,
  27923. iframe: iframeDataProcessor,
  27924. imagepreview: imagePreviewDataProcessor,
  27925. selectbox: selectBoxDataProcessor,
  27926. sizeinput: sizeInputDataProcessor,
  27927. slider: sliderInputDataProcessor,
  27928. listbox: listBoxDataProcessor,
  27929. size: sizeInputDataProcessor,
  27930. textarea: textAreaDataProcessor,
  27931. urlinput: urlInputDataProcessor,
  27932. customeditor: customEditorDataProcessor,
  27933. collection: collectionDataProcessor,
  27934. togglemenuitem: dialogToggleMenuItemDataProcessor
  27935. };
  27936. const getDataProcessor = item => Optional.from(dataProcessors[item.type]);
  27937. const getNamedItems = structure => filter$2(getAllObjects(structure), isNamedItem);
  27938. const createDataValidator = structure => {
  27939. const namedItems = getNamedItems(structure);
  27940. const fields = bind$3(namedItems, item => getDataProcessor(item).fold(() => [], schema => [requiredOf(item.name, schema)]));
  27941. return objOf(fields);
  27942. };
  27943. const extract = structure => {
  27944. var _a;
  27945. const internalDialog = getOrDie(createDialog(structure));
  27946. const dataValidator = createDataValidator(structure);
  27947. const initialData = (_a = structure.initialData) !== null && _a !== void 0 ? _a : {};
  27948. return {
  27949. internalDialog,
  27950. dataValidator,
  27951. initialData
  27952. };
  27953. };
  27954. const DialogManager = {
  27955. open: (factory, structure) => {
  27956. const extraction = extract(structure);
  27957. return factory(extraction.internalDialog, extraction.initialData, extraction.dataValidator);
  27958. },
  27959. openUrl: (factory, structure) => {
  27960. const internalDialog = getOrDie(createUrlDialog(structure));
  27961. return factory(internalDialog);
  27962. },
  27963. redial: structure => extract(structure)
  27964. };
  27965. const events = (reflectingConfig, reflectingState) => {
  27966. const update = (component, data) => {
  27967. reflectingConfig.updateState.each(updateState => {
  27968. const newState = updateState(component, data);
  27969. reflectingState.set(newState);
  27970. });
  27971. reflectingConfig.renderComponents.each(renderComponents => {
  27972. const newComponents = renderComponents(data, reflectingState.get());
  27973. const replacer = reflectingConfig.reuseDom ? withReuse : withoutReuse;
  27974. replacer(component, newComponents);
  27975. });
  27976. };
  27977. return derive$2([
  27978. run$1(receive(), (component, message) => {
  27979. const receivingData = message;
  27980. if (!receivingData.universal) {
  27981. const channel = reflectingConfig.channel;
  27982. if (contains$2(receivingData.channels, channel)) {
  27983. update(component, receivingData.data);
  27984. }
  27985. }
  27986. }),
  27987. runOnAttached((comp, _se) => {
  27988. reflectingConfig.initialData.each(rawData => {
  27989. update(comp, rawData);
  27990. });
  27991. })
  27992. ]);
  27993. };
  27994. var ActiveReflecting = /*#__PURE__*/Object.freeze({
  27995. __proto__: null,
  27996. events: events
  27997. });
  27998. const getState = (component, replaceConfig, reflectState) => reflectState;
  27999. var ReflectingApis = /*#__PURE__*/Object.freeze({
  28000. __proto__: null,
  28001. getState: getState
  28002. });
  28003. var ReflectingSchema = [
  28004. required$1('channel'),
  28005. option$3('renderComponents'),
  28006. option$3('updateState'),
  28007. option$3('initialData'),
  28008. defaultedBoolean('reuseDom', true)
  28009. ];
  28010. const init = () => {
  28011. const cell = Cell(Optional.none());
  28012. const clear = () => cell.set(Optional.none());
  28013. const readState = () => cell.get().getOr('none');
  28014. return {
  28015. readState,
  28016. get: cell.get,
  28017. set: cell.set,
  28018. clear
  28019. };
  28020. };
  28021. var ReflectingState = /*#__PURE__*/Object.freeze({
  28022. __proto__: null,
  28023. init: init
  28024. });
  28025. const Reflecting = create$4({
  28026. fields: ReflectingSchema,
  28027. name: 'reflecting',
  28028. active: ActiveReflecting,
  28029. apis: ReflectingApis,
  28030. state: ReflectingState
  28031. });
  28032. const toValidValues = values => {
  28033. const errors = [];
  28034. const result = {};
  28035. each(values, (value, name) => {
  28036. value.fold(() => {
  28037. errors.push(name);
  28038. }, v => {
  28039. result[name] = v;
  28040. });
  28041. });
  28042. return errors.length > 0 ? Result.error(errors) : Result.value(result);
  28043. };
  28044. const renderBodyPanel = (spec, dialogData, backstage) => {
  28045. const memForm = record(Form.sketch(parts => ({
  28046. dom: {
  28047. tag: 'div',
  28048. classes: ['tox-form'].concat(spec.classes)
  28049. },
  28050. components: map$2(spec.items, item => interpretInForm(parts, item, dialogData, backstage))
  28051. })));
  28052. return {
  28053. dom: {
  28054. tag: 'div',
  28055. classes: ['tox-dialog__body']
  28056. },
  28057. components: [{
  28058. dom: {
  28059. tag: 'div',
  28060. classes: ['tox-dialog__body-content']
  28061. },
  28062. components: [memForm.asSpec()]
  28063. }],
  28064. behaviours: derive$1([
  28065. Keying.config({
  28066. mode: 'acyclic',
  28067. useTabstopAt: not(isPseudoStop)
  28068. }),
  28069. ComposingConfigs.memento(memForm),
  28070. memento(memForm, {
  28071. postprocess: formValue => toValidValues(formValue).fold(err => {
  28072. console.error(err);
  28073. return {};
  28074. }, identity)
  28075. }),
  28076. config('dialog-body-panel', [run$1(focusin(), (comp, se) => {
  28077. comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: Optional.some(se.event.target) });
  28078. })])
  28079. ])
  28080. };
  28081. };
  28082. const factory$3 = (detail, _spec) => ({
  28083. uid: detail.uid,
  28084. dom: detail.dom,
  28085. components: detail.components,
  28086. events: events$a(detail.action),
  28087. behaviours: augment(detail.tabButtonBehaviours, [
  28088. Focusing.config({}),
  28089. Keying.config({
  28090. mode: 'execution',
  28091. useSpace: true,
  28092. useEnter: true
  28093. }),
  28094. Representing.config({
  28095. store: {
  28096. mode: 'memory',
  28097. initialValue: detail.value
  28098. }
  28099. })
  28100. ]),
  28101. domModification: detail.domModification
  28102. });
  28103. const TabButton = single({
  28104. name: 'TabButton',
  28105. configFields: [
  28106. defaulted('uid', undefined),
  28107. required$1('value'),
  28108. field$1('dom', 'dom', mergeWithThunk(() => ({
  28109. attributes: {
  28110. 'role': 'tab',
  28111. 'id': generate$6('aria'),
  28112. 'aria-selected': 'false'
  28113. }
  28114. })), anyValue()),
  28115. option$3('action'),
  28116. defaulted('domModification', {}),
  28117. field('tabButtonBehaviours', [
  28118. Focusing,
  28119. Keying,
  28120. Representing
  28121. ]),
  28122. required$1('view')
  28123. ],
  28124. factory: factory$3
  28125. });
  28126. const schema$1 = constant$1([
  28127. required$1('tabs'),
  28128. required$1('dom'),
  28129. defaulted('clickToDismiss', false),
  28130. field('tabbarBehaviours', [
  28131. Highlighting,
  28132. Keying
  28133. ]),
  28134. markers$1([
  28135. 'tabClass',
  28136. 'selectedClass'
  28137. ])
  28138. ]);
  28139. const tabsPart = group({
  28140. factory: TabButton,
  28141. name: 'tabs',
  28142. unit: 'tab',
  28143. overrides: barDetail => {
  28144. const dismissTab$1 = (tabbar, button) => {
  28145. Highlighting.dehighlight(tabbar, button);
  28146. emitWith(tabbar, dismissTab(), {
  28147. tabbar,
  28148. button
  28149. });
  28150. };
  28151. const changeTab$1 = (tabbar, button) => {
  28152. Highlighting.highlight(tabbar, button);
  28153. emitWith(tabbar, changeTab(), {
  28154. tabbar,
  28155. button
  28156. });
  28157. };
  28158. return {
  28159. action: button => {
  28160. const tabbar = button.getSystem().getByUid(barDetail.uid).getOrDie();
  28161. const activeButton = Highlighting.isHighlighted(tabbar, button);
  28162. const response = (() => {
  28163. if (activeButton && barDetail.clickToDismiss) {
  28164. return dismissTab$1;
  28165. } else if (!activeButton) {
  28166. return changeTab$1;
  28167. } else {
  28168. return noop;
  28169. }
  28170. })();
  28171. response(tabbar, button);
  28172. },
  28173. domModification: { classes: [barDetail.markers.tabClass] }
  28174. };
  28175. }
  28176. });
  28177. const parts$1 = constant$1([tabsPart]);
  28178. const factory$2 = (detail, components, _spec, _externals) => ({
  28179. 'uid': detail.uid,
  28180. 'dom': detail.dom,
  28181. components,
  28182. 'debug.sketcher': 'Tabbar',
  28183. 'domModification': { attributes: { role: 'tablist' } },
  28184. 'behaviours': augment(detail.tabbarBehaviours, [
  28185. Highlighting.config({
  28186. highlightClass: detail.markers.selectedClass,
  28187. itemClass: detail.markers.tabClass,
  28188. onHighlight: (tabbar, tab) => {
  28189. set$9(tab.element, 'aria-selected', 'true');
  28190. },
  28191. onDehighlight: (tabbar, tab) => {
  28192. set$9(tab.element, 'aria-selected', 'false');
  28193. }
  28194. }),
  28195. Keying.config({
  28196. mode: 'flow',
  28197. getInitial: tabbar => {
  28198. return Highlighting.getHighlighted(tabbar).map(tab => tab.element);
  28199. },
  28200. selector: '.' + detail.markers.tabClass,
  28201. executeOnMove: true
  28202. })
  28203. ])
  28204. });
  28205. const Tabbar = composite({
  28206. name: 'Tabbar',
  28207. configFields: schema$1(),
  28208. partFields: parts$1(),
  28209. factory: factory$2
  28210. });
  28211. const factory$1 = (detail, _spec) => ({
  28212. uid: detail.uid,
  28213. dom: detail.dom,
  28214. behaviours: augment(detail.tabviewBehaviours, [Replacing.config({})]),
  28215. domModification: { attributes: { role: 'tabpanel' } }
  28216. });
  28217. const Tabview = single({
  28218. name: 'Tabview',
  28219. configFields: [field('tabviewBehaviours', [Replacing])],
  28220. factory: factory$1
  28221. });
  28222. const schema = constant$1([
  28223. defaulted('selectFirst', true),
  28224. onHandler('onChangeTab'),
  28225. onHandler('onDismissTab'),
  28226. defaulted('tabs', []),
  28227. field('tabSectionBehaviours', [])
  28228. ]);
  28229. const barPart = required({
  28230. factory: Tabbar,
  28231. schema: [
  28232. required$1('dom'),
  28233. requiredObjOf('markers', [
  28234. required$1('tabClass'),
  28235. required$1('selectedClass')
  28236. ])
  28237. ],
  28238. name: 'tabbar',
  28239. defaults: detail => {
  28240. return { tabs: detail.tabs };
  28241. }
  28242. });
  28243. const viewPart = required({
  28244. factory: Tabview,
  28245. name: 'tabview'
  28246. });
  28247. const parts = constant$1([
  28248. barPart,
  28249. viewPart
  28250. ]);
  28251. const factory = (detail, components, _spec, _externals) => {
  28252. const changeTab$1 = button => {
  28253. const tabValue = Representing.getValue(button);
  28254. getPart(button, detail, 'tabview').each(tabview => {
  28255. const tabWithValue = find$5(detail.tabs, t => t.value === tabValue);
  28256. tabWithValue.each(tabData => {
  28257. const panel = tabData.view();
  28258. getOpt(button.element, 'id').each(id => {
  28259. set$9(tabview.element, 'aria-labelledby', id);
  28260. });
  28261. Replacing.set(tabview, panel);
  28262. detail.onChangeTab(tabview, button, panel);
  28263. });
  28264. });
  28265. };
  28266. const changeTabBy = (section, byPred) => {
  28267. getPart(section, detail, 'tabbar').each(tabbar => {
  28268. byPred(tabbar).each(emitExecute);
  28269. });
  28270. };
  28271. return {
  28272. uid: detail.uid,
  28273. dom: detail.dom,
  28274. components,
  28275. behaviours: get$3(detail.tabSectionBehaviours),
  28276. events: derive$2(flatten([
  28277. detail.selectFirst ? [runOnAttached((section, _simulatedEvent) => {
  28278. changeTabBy(section, Highlighting.getFirst);
  28279. })] : [],
  28280. [
  28281. run$1(changeTab(), (section, simulatedEvent) => {
  28282. const button = simulatedEvent.event.button;
  28283. changeTab$1(button);
  28284. }),
  28285. run$1(dismissTab(), (section, simulatedEvent) => {
  28286. const button = simulatedEvent.event.button;
  28287. detail.onDismissTab(section, button);
  28288. })
  28289. ]
  28290. ])),
  28291. apis: {
  28292. getViewItems: section => {
  28293. return getPart(section, detail, 'tabview').map(tabview => Replacing.contents(tabview)).getOr([]);
  28294. },
  28295. showTab: (section, tabKey) => {
  28296. const getTabIfNotActive = tabbar => {
  28297. const candidates = Highlighting.getCandidates(tabbar);
  28298. const optTab = find$5(candidates, c => Representing.getValue(c) === tabKey);
  28299. return optTab.filter(tab => !Highlighting.isHighlighted(tabbar, tab));
  28300. };
  28301. changeTabBy(section, getTabIfNotActive);
  28302. }
  28303. }
  28304. };
  28305. };
  28306. const TabSection = composite({
  28307. name: 'TabSection',
  28308. configFields: schema(),
  28309. partFields: parts(),
  28310. factory,
  28311. apis: {
  28312. getViewItems: (apis, component) => apis.getViewItems(component),
  28313. showTab: (apis, component, tabKey) => {
  28314. apis.showTab(component, tabKey);
  28315. }
  28316. }
  28317. });
  28318. const measureHeights = (allTabs, tabview, tabviewComp) => map$2(allTabs, (_tab, i) => {
  28319. Replacing.set(tabviewComp, allTabs[i].view());
  28320. const rect = tabview.dom.getBoundingClientRect();
  28321. Replacing.set(tabviewComp, []);
  28322. return rect.height;
  28323. });
  28324. const getMaxHeight = heights => head(sort(heights, (a, b) => {
  28325. if (a > b) {
  28326. return -1;
  28327. } else if (a < b) {
  28328. return +1;
  28329. } else {
  28330. return 0;
  28331. }
  28332. }));
  28333. const getMaxTabviewHeight = (dialog, tabview, tablist) => {
  28334. const documentElement$1 = documentElement(dialog).dom;
  28335. const rootElm = ancestor(dialog, '.tox-dialog-wrap').getOr(dialog);
  28336. const isFixed = get$e(rootElm, 'position') === 'fixed';
  28337. let maxHeight;
  28338. if (isFixed) {
  28339. maxHeight = Math.max(documentElement$1.clientHeight, window.innerHeight);
  28340. } else {
  28341. maxHeight = Math.max(documentElement$1.offsetHeight, documentElement$1.scrollHeight);
  28342. }
  28343. const tabviewHeight = get$d(tabview);
  28344. const isTabListBeside = tabview.dom.offsetLeft >= tablist.dom.offsetLeft + get$c(tablist);
  28345. const currentTabHeight = isTabListBeside ? Math.max(get$d(tablist), tabviewHeight) : tabviewHeight;
  28346. const dialogTopMargin = parseInt(get$e(dialog, 'margin-top'), 10) || 0;
  28347. const dialogBottomMargin = parseInt(get$e(dialog, 'margin-bottom'), 10) || 0;
  28348. const dialogHeight = get$d(dialog) + dialogTopMargin + dialogBottomMargin;
  28349. const chromeHeight = dialogHeight - currentTabHeight;
  28350. return maxHeight - chromeHeight;
  28351. };
  28352. const showTab = (allTabs, comp) => {
  28353. head(allTabs).each(tab => TabSection.showTab(comp, tab.value));
  28354. };
  28355. const setTabviewHeight = (tabview, height) => {
  28356. set$8(tabview, 'height', height + 'px');
  28357. set$8(tabview, 'flex-basis', height + 'px');
  28358. };
  28359. const updateTabviewHeight = (dialogBody, tabview, maxTabHeight) => {
  28360. ancestor(dialogBody, '[role="dialog"]').each(dialog => {
  28361. descendant(dialog, '[role="tablist"]').each(tablist => {
  28362. maxTabHeight.get().map(height => {
  28363. set$8(tabview, 'height', '0');
  28364. set$8(tabview, 'flex-basis', '0');
  28365. return Math.min(height, getMaxTabviewHeight(dialog, tabview, tablist));
  28366. }).each(height => {
  28367. setTabviewHeight(tabview, height);
  28368. });
  28369. });
  28370. });
  28371. };
  28372. const getTabview = dialog => descendant(dialog, '[role="tabpanel"]');
  28373. const smartMode = allTabs => {
  28374. const maxTabHeight = value$2();
  28375. const extraEvents = [
  28376. runOnAttached(comp => {
  28377. const dialog = comp.element;
  28378. getTabview(dialog).each(tabview => {
  28379. set$8(tabview, 'visibility', 'hidden');
  28380. comp.getSystem().getByDom(tabview).toOptional().each(tabviewComp => {
  28381. const heights = measureHeights(allTabs, tabview, tabviewComp);
  28382. const maxTabHeightOpt = getMaxHeight(heights);
  28383. maxTabHeightOpt.fold(maxTabHeight.clear, maxTabHeight.set);
  28384. });
  28385. updateTabviewHeight(dialog, tabview, maxTabHeight);
  28386. remove$6(tabview, 'visibility');
  28387. showTab(allTabs, comp);
  28388. requestAnimationFrame(() => {
  28389. updateTabviewHeight(dialog, tabview, maxTabHeight);
  28390. });
  28391. });
  28392. }),
  28393. run$1(windowResize(), comp => {
  28394. const dialog = comp.element;
  28395. getTabview(dialog).each(tabview => {
  28396. updateTabviewHeight(dialog, tabview, maxTabHeight);
  28397. });
  28398. }),
  28399. run$1(formResizeEvent, (comp, _se) => {
  28400. const dialog = comp.element;
  28401. getTabview(dialog).each(tabview => {
  28402. const oldFocus = active$1(getRootNode(tabview));
  28403. set$8(tabview, 'visibility', 'hidden');
  28404. const oldHeight = getRaw(tabview, 'height').map(h => parseInt(h, 10));
  28405. remove$6(tabview, 'height');
  28406. remove$6(tabview, 'flex-basis');
  28407. const newHeight = tabview.dom.getBoundingClientRect().height;
  28408. const hasGrown = oldHeight.forall(h => newHeight > h);
  28409. if (hasGrown) {
  28410. maxTabHeight.set(newHeight);
  28411. updateTabviewHeight(dialog, tabview, maxTabHeight);
  28412. } else {
  28413. oldHeight.each(h => {
  28414. setTabviewHeight(tabview, h);
  28415. });
  28416. }
  28417. remove$6(tabview, 'visibility');
  28418. oldFocus.each(focus$3);
  28419. });
  28420. })
  28421. ];
  28422. const selectFirst = false;
  28423. return {
  28424. extraEvents,
  28425. selectFirst
  28426. };
  28427. };
  28428. const SendDataToSectionChannel = 'send-data-to-section';
  28429. const SendDataToViewChannel = 'send-data-to-view';
  28430. const renderTabPanel = (spec, dialogData, backstage) => {
  28431. const storedValue = Cell({});
  28432. const updateDataWithForm = form => {
  28433. const formData = Representing.getValue(form);
  28434. const validData = toValidValues(formData).getOr({});
  28435. const currentData = storedValue.get();
  28436. const newData = deepMerge(currentData, validData);
  28437. storedValue.set(newData);
  28438. };
  28439. const setDataOnForm = form => {
  28440. const tabData = storedValue.get();
  28441. Representing.setValue(form, tabData);
  28442. };
  28443. const oldTab = Cell(null);
  28444. const allTabs = map$2(spec.tabs, tab => {
  28445. return {
  28446. value: tab.name,
  28447. dom: {
  28448. tag: 'div',
  28449. classes: ['tox-dialog__body-nav-item']
  28450. },
  28451. components: [text$2(backstage.shared.providers.translate(tab.title))],
  28452. view: () => {
  28453. return [Form.sketch(parts => ({
  28454. dom: {
  28455. tag: 'div',
  28456. classes: ['tox-form']
  28457. },
  28458. components: map$2(tab.items, item => interpretInForm(parts, item, dialogData, backstage)),
  28459. formBehaviours: derive$1([
  28460. Keying.config({
  28461. mode: 'acyclic',
  28462. useTabstopAt: not(isPseudoStop)
  28463. }),
  28464. config('TabView.form.events', [
  28465. runOnAttached(setDataOnForm),
  28466. runOnDetached(updateDataWithForm)
  28467. ]),
  28468. Receiving.config({
  28469. channels: wrapAll([
  28470. {
  28471. key: SendDataToSectionChannel,
  28472. value: { onReceive: updateDataWithForm }
  28473. },
  28474. {
  28475. key: SendDataToViewChannel,
  28476. value: { onReceive: setDataOnForm }
  28477. }
  28478. ])
  28479. })
  28480. ])
  28481. }))];
  28482. }
  28483. };
  28484. });
  28485. const tabMode = smartMode(allTabs);
  28486. return TabSection.sketch({
  28487. dom: {
  28488. tag: 'div',
  28489. classes: ['tox-dialog__body']
  28490. },
  28491. onChangeTab: (section, button, _viewItems) => {
  28492. const name = Representing.getValue(button);
  28493. emitWith(section, formTabChangeEvent, {
  28494. name,
  28495. oldName: oldTab.get()
  28496. });
  28497. oldTab.set(name);
  28498. },
  28499. tabs: allTabs,
  28500. components: [
  28501. TabSection.parts.tabbar({
  28502. dom: {
  28503. tag: 'div',
  28504. classes: ['tox-dialog__body-nav']
  28505. },
  28506. components: [Tabbar.parts.tabs({})],
  28507. markers: {
  28508. tabClass: 'tox-tab',
  28509. selectedClass: 'tox-dialog__body-nav-item--active'
  28510. },
  28511. tabbarBehaviours: derive$1([Tabstopping.config({})])
  28512. }),
  28513. TabSection.parts.tabview({
  28514. dom: {
  28515. tag: 'div',
  28516. classes: ['tox-dialog__body-content']
  28517. }
  28518. })
  28519. ],
  28520. selectFirst: tabMode.selectFirst,
  28521. tabSectionBehaviours: derive$1([
  28522. config('tabpanel', tabMode.extraEvents),
  28523. Keying.config({ mode: 'acyclic' }),
  28524. Composing.config({ find: comp => head(TabSection.getViewItems(comp)) }),
  28525. withComp(Optional.none(), tsection => {
  28526. tsection.getSystem().broadcastOn([SendDataToSectionChannel], {});
  28527. return storedValue.get();
  28528. }, (tsection, value) => {
  28529. storedValue.set(value);
  28530. tsection.getSystem().broadcastOn([SendDataToViewChannel], {});
  28531. })
  28532. ])
  28533. });
  28534. };
  28535. const renderBody = (spec, dialogId, contentId, backstage, ariaAttrs) => {
  28536. const renderComponents = incoming => {
  28537. const body = incoming.body;
  28538. switch (body.type) {
  28539. case 'tabpanel': {
  28540. return [renderTabPanel(body, incoming.initialData, backstage)];
  28541. }
  28542. default: {
  28543. return [renderBodyPanel(body, incoming.initialData, backstage)];
  28544. }
  28545. }
  28546. };
  28547. const updateState = (_comp, incoming) => Optional.some({ isTabPanel: () => incoming.body.type === 'tabpanel' });
  28548. const ariaAttributes = { 'aria-live': 'polite' };
  28549. return {
  28550. dom: {
  28551. tag: 'div',
  28552. classes: ['tox-dialog__content-js'],
  28553. attributes: {
  28554. ...contentId.map(x => ({ id: x })).getOr({}),
  28555. ...ariaAttrs ? ariaAttributes : {}
  28556. }
  28557. },
  28558. components: [],
  28559. behaviours: derive$1([
  28560. ComposingConfigs.childAt(0),
  28561. Reflecting.config({
  28562. channel: `${ bodyChannel }-${ dialogId }`,
  28563. updateState,
  28564. renderComponents,
  28565. initialData: spec
  28566. })
  28567. ])
  28568. };
  28569. };
  28570. const renderInlineBody = (spec, dialogId, contentId, backstage, ariaAttrs) => renderBody(spec, dialogId, Optional.some(contentId), backstage, ariaAttrs);
  28571. const renderModalBody = (spec, dialogId, backstage) => {
  28572. const bodySpec = renderBody(spec, dialogId, Optional.none(), backstage, false);
  28573. return ModalDialog.parts.body(bodySpec);
  28574. };
  28575. const renderIframeBody = spec => {
  28576. const bodySpec = {
  28577. dom: {
  28578. tag: 'div',
  28579. classes: ['tox-dialog__content-js']
  28580. },
  28581. components: [{
  28582. dom: {
  28583. tag: 'div',
  28584. classes: ['tox-dialog__body-iframe']
  28585. },
  28586. components: [craft(Optional.none(), {
  28587. dom: {
  28588. tag: 'iframe',
  28589. attributes: { src: spec.url }
  28590. },
  28591. behaviours: derive$1([
  28592. Tabstopping.config({}),
  28593. Focusing.config({})
  28594. ])
  28595. })]
  28596. }],
  28597. behaviours: derive$1([Keying.config({
  28598. mode: 'acyclic',
  28599. useTabstopAt: not(isPseudoStop)
  28600. })])
  28601. };
  28602. return ModalDialog.parts.body(bodySpec);
  28603. };
  28604. const isTouch = global$5.deviceType.isTouch();
  28605. const hiddenHeader = (title, close) => ({
  28606. dom: {
  28607. tag: 'div',
  28608. styles: { display: 'none' },
  28609. classes: ['tox-dialog__header']
  28610. },
  28611. components: [
  28612. title,
  28613. close
  28614. ]
  28615. });
  28616. const pClose = (onClose, providersBackstage) => ModalDialog.parts.close(Button.sketch({
  28617. dom: {
  28618. tag: 'button',
  28619. classes: [
  28620. 'tox-button',
  28621. 'tox-button--icon',
  28622. 'tox-button--naked'
  28623. ],
  28624. attributes: {
  28625. 'type': 'button',
  28626. 'aria-label': providersBackstage.translate('Close')
  28627. }
  28628. },
  28629. action: onClose,
  28630. buttonBehaviours: derive$1([Tabstopping.config({})])
  28631. }));
  28632. const pUntitled = () => ModalDialog.parts.title({
  28633. dom: {
  28634. tag: 'div',
  28635. classes: ['tox-dialog__title'],
  28636. innerHtml: '',
  28637. styles: { display: 'none' }
  28638. }
  28639. });
  28640. const pBodyMessage = (message, providersBackstage) => ModalDialog.parts.body({
  28641. dom: {
  28642. tag: 'div',
  28643. classes: ['tox-dialog__body']
  28644. },
  28645. components: [{
  28646. dom: {
  28647. tag: 'div',
  28648. classes: ['tox-dialog__body-content']
  28649. },
  28650. components: [{ dom: fromHtml(`<p>${ sanitizeHtmlString(providersBackstage.translate(message)) }</p>`) }]
  28651. }]
  28652. });
  28653. const pFooter = buttons => ModalDialog.parts.footer({
  28654. dom: {
  28655. tag: 'div',
  28656. classes: ['tox-dialog__footer']
  28657. },
  28658. components: buttons
  28659. });
  28660. const pFooterGroup = (startButtons, endButtons) => [
  28661. Container.sketch({
  28662. dom: {
  28663. tag: 'div',
  28664. classes: ['tox-dialog__footer-start']
  28665. },
  28666. components: startButtons
  28667. }),
  28668. Container.sketch({
  28669. dom: {
  28670. tag: 'div',
  28671. classes: ['tox-dialog__footer-end']
  28672. },
  28673. components: endButtons
  28674. })
  28675. ];
  28676. const renderDialog$1 = spec => {
  28677. const dialogClass = 'tox-dialog';
  28678. const blockerClass = dialogClass + '-wrap';
  28679. const blockerBackdropClass = blockerClass + '__backdrop';
  28680. const scrollLockClass = dialogClass + '__disable-scroll';
  28681. return ModalDialog.sketch({
  28682. lazySink: spec.lazySink,
  28683. onEscape: comp => {
  28684. spec.onEscape(comp);
  28685. return Optional.some(true);
  28686. },
  28687. useTabstopAt: elem => !isPseudoStop(elem),
  28688. firstTabstop: spec.firstTabstop,
  28689. dom: {
  28690. tag: 'div',
  28691. classes: [dialogClass].concat(spec.extraClasses),
  28692. styles: {
  28693. position: 'relative',
  28694. ...spec.extraStyles
  28695. }
  28696. },
  28697. components: [
  28698. spec.header,
  28699. spec.body,
  28700. ...spec.footer.toArray()
  28701. ],
  28702. parts: {
  28703. blocker: {
  28704. dom: fromHtml(`<div class="${ blockerClass }"></div>`),
  28705. components: [{
  28706. dom: {
  28707. tag: 'div',
  28708. classes: isTouch ? [
  28709. blockerBackdropClass,
  28710. blockerBackdropClass + '--opaque'
  28711. ] : [blockerBackdropClass]
  28712. }
  28713. }]
  28714. }
  28715. },
  28716. dragBlockClass: blockerClass,
  28717. modalBehaviours: derive$1([
  28718. Focusing.config({}),
  28719. config('dialog-events', spec.dialogEvents.concat([
  28720. runOnSource(focusin(), (comp, _se) => {
  28721. Blocking.isBlocked(comp) ? noop() : Keying.focusIn(comp);
  28722. }),
  28723. run$1(focusShifted(), (comp, se) => {
  28724. comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: se.event.newFocus });
  28725. })
  28726. ])),
  28727. config('scroll-lock', [
  28728. runOnAttached(() => {
  28729. add$2(body(), scrollLockClass);
  28730. }),
  28731. runOnDetached(() => {
  28732. remove$2(body(), scrollLockClass);
  28733. })
  28734. ]),
  28735. ...spec.extraBehaviours
  28736. ]),
  28737. eventOrder: {
  28738. [execute$5()]: ['dialog-events'],
  28739. [attachedToDom()]: [
  28740. 'scroll-lock',
  28741. 'dialog-events',
  28742. 'alloy.base.behaviour'
  28743. ],
  28744. [detachedFromDom()]: [
  28745. 'alloy.base.behaviour',
  28746. 'dialog-events',
  28747. 'scroll-lock'
  28748. ],
  28749. ...spec.eventOrder
  28750. }
  28751. });
  28752. };
  28753. const renderClose = providersBackstage => Button.sketch({
  28754. dom: {
  28755. tag: 'button',
  28756. classes: [
  28757. 'tox-button',
  28758. 'tox-button--icon',
  28759. 'tox-button--naked'
  28760. ],
  28761. attributes: {
  28762. 'type': 'button',
  28763. 'aria-label': providersBackstage.translate('Close'),
  28764. 'title': providersBackstage.translate('Close')
  28765. }
  28766. },
  28767. buttonBehaviours: derive$1([Tabstopping.config({})]),
  28768. components: [render$3('close', {
  28769. tag: 'span',
  28770. classes: ['tox-icon']
  28771. }, providersBackstage.icons)],
  28772. action: comp => {
  28773. emit(comp, formCancelEvent);
  28774. }
  28775. });
  28776. const renderTitle = (spec, dialogId, titleId, providersBackstage) => {
  28777. const renderComponents = data => [text$2(providersBackstage.translate(data.title))];
  28778. return {
  28779. dom: {
  28780. tag: 'div',
  28781. classes: ['tox-dialog__title'],
  28782. attributes: { ...titleId.map(x => ({ id: x })).getOr({}) }
  28783. },
  28784. components: [],
  28785. behaviours: derive$1([Reflecting.config({
  28786. channel: `${ titleChannel }-${ dialogId }`,
  28787. initialData: spec,
  28788. renderComponents
  28789. })])
  28790. };
  28791. };
  28792. const renderDragHandle = () => ({ dom: fromHtml('<div class="tox-dialog__draghandle"></div>') });
  28793. const renderInlineHeader = (spec, dialogId, titleId, providersBackstage) => Container.sketch({
  28794. dom: fromHtml('<div class="tox-dialog__header"></div>'),
  28795. components: [
  28796. renderTitle(spec, dialogId, Optional.some(titleId), providersBackstage),
  28797. renderDragHandle(),
  28798. renderClose(providersBackstage)
  28799. ],
  28800. containerBehaviours: derive$1([Dragging.config({
  28801. mode: 'mouse',
  28802. blockerClass: 'blocker',
  28803. getTarget: handle => {
  28804. return closest$1(handle, '[role="dialog"]').getOrDie();
  28805. },
  28806. snaps: {
  28807. getSnapPoints: () => [],
  28808. leftAttr: 'data-drag-left',
  28809. topAttr: 'data-drag-top'
  28810. }
  28811. })])
  28812. });
  28813. const renderModalHeader = (spec, dialogId, providersBackstage) => {
  28814. const pTitle = ModalDialog.parts.title(renderTitle(spec, dialogId, Optional.none(), providersBackstage));
  28815. const pHandle = ModalDialog.parts.draghandle(renderDragHandle());
  28816. const pClose = ModalDialog.parts.close(renderClose(providersBackstage));
  28817. const components = [pTitle].concat(spec.draggable ? [pHandle] : []).concat([pClose]);
  28818. return Container.sketch({
  28819. dom: fromHtml('<div class="tox-dialog__header"></div>'),
  28820. components
  28821. });
  28822. };
  28823. const getHeader = (title, dialogId, backstage) => renderModalHeader({
  28824. title: backstage.shared.providers.translate(title),
  28825. draggable: backstage.dialog.isDraggableModal()
  28826. }, dialogId, backstage.shared.providers);
  28827. const getBusySpec = (message, bs, providers, headerHeight) => ({
  28828. dom: {
  28829. tag: 'div',
  28830. classes: ['tox-dialog__busy-spinner'],
  28831. attributes: { 'aria-label': providers.translate(message) },
  28832. styles: {
  28833. left: '0px',
  28834. right: '0px',
  28835. bottom: '0px',
  28836. top: `${ headerHeight.getOr(0) }px`,
  28837. position: 'absolute'
  28838. }
  28839. },
  28840. behaviours: bs,
  28841. components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  28842. });
  28843. const getEventExtras = (lazyDialog, providers, extra) => ({
  28844. onClose: () => extra.closeWindow(),
  28845. onBlock: blockEvent => {
  28846. const headerHeight = descendant(lazyDialog().element, '.tox-dialog__header').map(header => get$d(header));
  28847. ModalDialog.setBusy(lazyDialog(), (_comp, bs) => getBusySpec(blockEvent.message, bs, providers, headerHeight));
  28848. },
  28849. onUnblock: () => {
  28850. ModalDialog.setIdle(lazyDialog());
  28851. }
  28852. });
  28853. const fullscreenClass = 'tox-dialog--fullscreen';
  28854. const largeDialogClass = 'tox-dialog--width-lg';
  28855. const mediumDialogClass = 'tox-dialog--width-md';
  28856. const getDialogSizeClass = size => {
  28857. switch (size) {
  28858. case 'large':
  28859. return Optional.some(largeDialogClass);
  28860. case 'medium':
  28861. return Optional.some(mediumDialogClass);
  28862. default:
  28863. return Optional.none();
  28864. }
  28865. };
  28866. const updateDialogSizeClass = (size, component) => {
  28867. const dialogBody = SugarElement.fromDom(component.element.dom);
  28868. if (!has(dialogBody, fullscreenClass)) {
  28869. remove$1(dialogBody, [
  28870. largeDialogClass,
  28871. mediumDialogClass
  28872. ]);
  28873. getDialogSizeClass(size).each(dialogSizeClass => add$2(dialogBody, dialogSizeClass));
  28874. }
  28875. };
  28876. const toggleFullscreen = (comp, currentSize) => {
  28877. const dialogBody = SugarElement.fromDom(comp.element.dom);
  28878. const classes = get$7(dialogBody);
  28879. const currentSizeClass = find$5(classes, c => c === largeDialogClass || c === mediumDialogClass).or(getDialogSizeClass(currentSize));
  28880. toggle$3(dialogBody, [
  28881. fullscreenClass,
  28882. ...currentSizeClass.toArray()
  28883. ]);
  28884. };
  28885. const renderModalDialog = (spec, dialogEvents, backstage) => build$1(renderDialog$1({
  28886. ...spec,
  28887. firstTabstop: 1,
  28888. lazySink: backstage.shared.getSink,
  28889. extraBehaviours: [
  28890. memory({}),
  28891. ...spec.extraBehaviours
  28892. ],
  28893. onEscape: comp => {
  28894. emit(comp, formCancelEvent);
  28895. },
  28896. dialogEvents,
  28897. eventOrder: {
  28898. [receive()]: [
  28899. Reflecting.name(),
  28900. Receiving.name()
  28901. ],
  28902. [attachedToDom()]: [
  28903. 'scroll-lock',
  28904. Reflecting.name(),
  28905. 'messages',
  28906. 'dialog-events',
  28907. 'alloy.base.behaviour'
  28908. ],
  28909. [detachedFromDom()]: [
  28910. 'alloy.base.behaviour',
  28911. 'dialog-events',
  28912. 'messages',
  28913. Reflecting.name(),
  28914. 'scroll-lock'
  28915. ]
  28916. }
  28917. }));
  28918. const mapMenuButtons = (buttons, menuItemStates = {}) => {
  28919. const mapItems = button => {
  28920. const items = map$2(button.items, item => {
  28921. const cell = get$g(menuItemStates, item.name).getOr(Cell(false));
  28922. return {
  28923. ...item,
  28924. storage: cell
  28925. };
  28926. });
  28927. return {
  28928. ...button,
  28929. items
  28930. };
  28931. };
  28932. return map$2(buttons, button => {
  28933. return button.type === 'menu' ? mapItems(button) : button;
  28934. });
  28935. };
  28936. const extractCellsToObject = buttons => foldl(buttons, (acc, button) => {
  28937. if (button.type === 'menu') {
  28938. const menuButton = button;
  28939. return foldl(menuButton.items, (innerAcc, item) => {
  28940. innerAcc[item.name] = item.storage;
  28941. return innerAcc;
  28942. }, acc);
  28943. }
  28944. return acc;
  28945. }, {});
  28946. const initCommonEvents = (fireApiEvent, extras) => [
  28947. runWithTarget(focusin(), onFocus),
  28948. fireApiEvent(formCloseEvent, (_api, spec, _event, self) => {
  28949. active$1(getRootNode(self.element)).fold(noop, blur$1);
  28950. extras.onClose();
  28951. spec.onClose();
  28952. }),
  28953. fireApiEvent(formCancelEvent, (api, spec, _event, self) => {
  28954. spec.onCancel(api);
  28955. emit(self, formCloseEvent);
  28956. }),
  28957. run$1(formUnblockEvent, (_c, _se) => extras.onUnblock()),
  28958. run$1(formBlockEvent, (_c, se) => extras.onBlock(se.event))
  28959. ];
  28960. const initUrlDialog = (getInstanceApi, extras) => {
  28961. const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
  28962. withSpec(c, (spec, _c) => {
  28963. f(getInstanceApi(), spec, se.event, c);
  28964. });
  28965. });
  28966. const withSpec = (c, f) => {
  28967. Reflecting.getState(c).get().each(currentDialog => {
  28968. f(currentDialog, c);
  28969. });
  28970. };
  28971. return [
  28972. ...initCommonEvents(fireApiEvent, extras),
  28973. fireApiEvent(formActionEvent, (api, spec, event) => {
  28974. spec.onAction(api, { name: event.name });
  28975. })
  28976. ];
  28977. };
  28978. const initDialog = (getInstanceApi, extras, getSink) => {
  28979. const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
  28980. withSpec(c, (spec, _c) => {
  28981. f(getInstanceApi(), spec, se.event, c);
  28982. });
  28983. });
  28984. const withSpec = (c, f) => {
  28985. Reflecting.getState(c).get().each(currentDialogInit => {
  28986. f(currentDialogInit.internalDialog, c);
  28987. });
  28988. };
  28989. return [
  28990. ...initCommonEvents(fireApiEvent, extras),
  28991. fireApiEvent(formSubmitEvent, (api, spec) => spec.onSubmit(api)),
  28992. fireApiEvent(formChangeEvent, (api, spec, event) => {
  28993. spec.onChange(api, { name: event.name });
  28994. }),
  28995. fireApiEvent(formActionEvent, (api, spec, event, component) => {
  28996. const focusIn = () => component.getSystem().isConnected() ? Keying.focusIn(component) : undefined;
  28997. const isDisabled = focused => has$1(focused, 'disabled') || getOpt(focused, 'aria-disabled').exists(val => val === 'true');
  28998. const rootNode = getRootNode(component.element);
  28999. const current = active$1(rootNode);
  29000. spec.onAction(api, {
  29001. name: event.name,
  29002. value: event.value
  29003. });
  29004. active$1(rootNode).fold(focusIn, focused => {
  29005. if (isDisabled(focused)) {
  29006. focusIn();
  29007. } else if (current.exists(cur => contains(focused, cur) && isDisabled(cur))) {
  29008. focusIn();
  29009. } else {
  29010. getSink().toOptional().filter(sink => !contains(sink.element, focused)).each(focusIn);
  29011. }
  29012. });
  29013. }),
  29014. fireApiEvent(formTabChangeEvent, (api, spec, event) => {
  29015. spec.onTabChange(api, {
  29016. newTabName: event.name,
  29017. oldTabName: event.oldName
  29018. });
  29019. }),
  29020. runOnDetached(component => {
  29021. const api = getInstanceApi();
  29022. Representing.setValue(component, api.getData());
  29023. })
  29024. ];
  29025. };
  29026. const makeButton = (button, backstage) => renderFooterButton(button, button.type, backstage);
  29027. const lookup = (compInSystem, footerButtons, buttonName) => find$5(footerButtons, button => button.name === buttonName).bind(memButton => memButton.memento.getOpt(compInSystem));
  29028. const renderComponents = (_data, state) => {
  29029. const footerButtons = state.map(s => s.footerButtons).getOr([]);
  29030. const buttonGroups = partition$3(footerButtons, button => button.align === 'start');
  29031. const makeGroup = (edge, buttons) => Container.sketch({
  29032. dom: {
  29033. tag: 'div',
  29034. classes: [`tox-dialog__footer-${ edge }`]
  29035. },
  29036. components: map$2(buttons, button => button.memento.asSpec())
  29037. });
  29038. const startButtons = makeGroup('start', buttonGroups.pass);
  29039. const endButtons = makeGroup('end', buttonGroups.fail);
  29040. return [
  29041. startButtons,
  29042. endButtons
  29043. ];
  29044. };
  29045. const renderFooter = (initSpec, dialogId, backstage) => {
  29046. const updateState = (comp, data) => {
  29047. const footerButtons = map$2(data.buttons, button => {
  29048. const memButton = record(makeButton(button, backstage));
  29049. return {
  29050. name: button.name,
  29051. align: button.align,
  29052. memento: memButton
  29053. };
  29054. });
  29055. const lookupByName = buttonName => lookup(comp, footerButtons, buttonName);
  29056. return Optional.some({
  29057. lookupByName,
  29058. footerButtons
  29059. });
  29060. };
  29061. return {
  29062. dom: fromHtml('<div class="tox-dialog__footer"></div>'),
  29063. components: [],
  29064. behaviours: derive$1([Reflecting.config({
  29065. channel: `${ footerChannel }-${ dialogId }`,
  29066. initialData: initSpec,
  29067. updateState,
  29068. renderComponents
  29069. })])
  29070. };
  29071. };
  29072. const renderInlineFooter = (initSpec, dialogId, backstage) => renderFooter(initSpec, dialogId, backstage);
  29073. const renderModalFooter = (initSpec, dialogId, backstage) => ModalDialog.parts.footer(renderFooter(initSpec, dialogId, backstage));
  29074. const getCompByName = (access, name) => {
  29075. const root = access.getRoot();
  29076. if (root.getSystem().isConnected()) {
  29077. const form = Composing.getCurrent(access.getFormWrapper()).getOr(access.getFormWrapper());
  29078. return Form.getField(form, name).orThunk(() => {
  29079. const footer = access.getFooter();
  29080. const footerState = footer.bind(f => Reflecting.getState(f).get());
  29081. return footerState.bind(f => f.lookupByName(name));
  29082. });
  29083. } else {
  29084. return Optional.none();
  29085. }
  29086. };
  29087. const validateData$1 = (access, data) => {
  29088. const root = access.getRoot();
  29089. return Reflecting.getState(root).get().map(dialogState => getOrDie(asRaw('data', dialogState.dataValidator, data))).getOr(data);
  29090. };
  29091. const getDialogApi = (access, doRedial, menuItemStates) => {
  29092. const withRoot = f => {
  29093. const root = access.getRoot();
  29094. if (root.getSystem().isConnected()) {
  29095. f(root);
  29096. }
  29097. };
  29098. const getData = () => {
  29099. const root = access.getRoot();
  29100. const valueComp = root.getSystem().isConnected() ? access.getFormWrapper() : root;
  29101. const representedValues = Representing.getValue(valueComp);
  29102. const menuItemCurrentState = map$1(menuItemStates, cell => cell.get());
  29103. return {
  29104. ...representedValues,
  29105. ...menuItemCurrentState
  29106. };
  29107. };
  29108. const setData = newData => {
  29109. withRoot(_ => {
  29110. const prevData = instanceApi.getData();
  29111. const mergedData = deepMerge(prevData, newData);
  29112. const newInternalData = validateData$1(access, mergedData);
  29113. const form = access.getFormWrapper();
  29114. Representing.setValue(form, newInternalData);
  29115. each(menuItemStates, (v, k) => {
  29116. if (has$2(mergedData, k)) {
  29117. v.set(mergedData[k]);
  29118. }
  29119. });
  29120. });
  29121. };
  29122. const setEnabled = (name, state) => {
  29123. getCompByName(access, name).each(state ? Disabling.enable : Disabling.disable);
  29124. };
  29125. const focus = name => {
  29126. getCompByName(access, name).each(Focusing.focus);
  29127. };
  29128. const block = message => {
  29129. if (!isString(message)) {
  29130. throw new Error('The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
  29131. }
  29132. withRoot(root => {
  29133. emitWith(root, formBlockEvent, { message });
  29134. });
  29135. };
  29136. const unblock = () => {
  29137. withRoot(root => {
  29138. emit(root, formUnblockEvent);
  29139. });
  29140. };
  29141. const showTab = name => {
  29142. withRoot(_ => {
  29143. const body = access.getBody();
  29144. const bodyState = Reflecting.getState(body);
  29145. if (bodyState.get().exists(b => b.isTabPanel())) {
  29146. Composing.getCurrent(body).each(tabSection => {
  29147. TabSection.showTab(tabSection, name);
  29148. });
  29149. }
  29150. });
  29151. };
  29152. const redial = d => {
  29153. withRoot(root => {
  29154. const id = access.getId();
  29155. const dialogInit = doRedial(d);
  29156. const storedMenuButtons = mapMenuButtons(dialogInit.internalDialog.buttons, menuItemStates);
  29157. root.getSystem().broadcastOn([`${ dialogChannel }-${ id }`], dialogInit);
  29158. root.getSystem().broadcastOn([`${ titleChannel }-${ id }`], dialogInit.internalDialog);
  29159. root.getSystem().broadcastOn([`${ bodyChannel }-${ id }`], dialogInit.internalDialog);
  29160. root.getSystem().broadcastOn([`${ footerChannel }-${ id }`], {
  29161. ...dialogInit.internalDialog,
  29162. buttons: storedMenuButtons
  29163. });
  29164. instanceApi.setData(dialogInit.initialData);
  29165. });
  29166. };
  29167. const close = () => {
  29168. withRoot(root => {
  29169. emit(root, formCloseEvent);
  29170. });
  29171. };
  29172. const instanceApi = {
  29173. getData,
  29174. setData,
  29175. setEnabled,
  29176. focus,
  29177. block,
  29178. unblock,
  29179. showTab,
  29180. redial,
  29181. close,
  29182. toggleFullscreen: access.toggleFullscreen
  29183. };
  29184. return instanceApi;
  29185. };
  29186. const renderDialog = (dialogInit, extra, backstage) => {
  29187. const dialogId = generate$6('dialog');
  29188. const internalDialog = dialogInit.internalDialog;
  29189. const header = getHeader(internalDialog.title, dialogId, backstage);
  29190. const dialogSize = Cell(internalDialog.size);
  29191. const dialogSizeClasses = getDialogSizeClass(dialogSize.get()).toArray();
  29192. const updateState = (comp, incoming) => {
  29193. dialogSize.set(incoming.internalDialog.size);
  29194. updateDialogSizeClass(incoming.internalDialog.size, comp);
  29195. return Optional.some(incoming);
  29196. };
  29197. const body = renderModalBody({
  29198. body: internalDialog.body,
  29199. initialData: internalDialog.initialData
  29200. }, dialogId, backstage);
  29201. const storedMenuButtons = mapMenuButtons(internalDialog.buttons);
  29202. const objOfCells = extractCellsToObject(storedMenuButtons);
  29203. const footer = someIf(storedMenuButtons.length !== 0, renderModalFooter({ buttons: storedMenuButtons }, dialogId, backstage));
  29204. const dialogEvents = initDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra), backstage.shared.getSink);
  29205. const spec = {
  29206. id: dialogId,
  29207. header,
  29208. body,
  29209. footer,
  29210. extraClasses: dialogSizeClasses,
  29211. extraBehaviours: [Reflecting.config({
  29212. channel: `${ dialogChannel }-${ dialogId }`,
  29213. updateState,
  29214. initialData: dialogInit
  29215. })],
  29216. extraStyles: {}
  29217. };
  29218. const dialog = renderModalDialog(spec, dialogEvents, backstage);
  29219. const modalAccess = (() => {
  29220. const getForm = () => {
  29221. const outerForm = ModalDialog.getBody(dialog);
  29222. return Composing.getCurrent(outerForm).getOr(outerForm);
  29223. };
  29224. const toggleFullscreen$1 = () => {
  29225. toggleFullscreen(dialog, dialogSize.get());
  29226. };
  29227. return {
  29228. getId: constant$1(dialogId),
  29229. getRoot: constant$1(dialog),
  29230. getBody: () => ModalDialog.getBody(dialog),
  29231. getFooter: () => ModalDialog.getFooter(dialog),
  29232. getFormWrapper: getForm,
  29233. toggleFullscreen: toggleFullscreen$1
  29234. };
  29235. })();
  29236. const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
  29237. return {
  29238. dialog,
  29239. instanceApi
  29240. };
  29241. };
  29242. const renderInlineDialog = (dialogInit, extra, backstage, ariaAttrs = false, refreshDocking) => {
  29243. const dialogId = generate$6('dialog');
  29244. const dialogLabelId = generate$6('dialog-label');
  29245. const dialogContentId = generate$6('dialog-content');
  29246. const internalDialog = dialogInit.internalDialog;
  29247. const dialogSize = Cell(internalDialog.size);
  29248. const dialogSizeClass = getDialogSizeClass(dialogSize.get()).toArray();
  29249. const updateState = (comp, incoming) => {
  29250. dialogSize.set(incoming.internalDialog.size);
  29251. updateDialogSizeClass(incoming.internalDialog.size, comp);
  29252. refreshDocking();
  29253. return Optional.some(incoming);
  29254. };
  29255. const memHeader = record(renderInlineHeader({
  29256. title: internalDialog.title,
  29257. draggable: true
  29258. }, dialogId, dialogLabelId, backstage.shared.providers));
  29259. const memBody = record(renderInlineBody({
  29260. body: internalDialog.body,
  29261. initialData: internalDialog.initialData
  29262. }, dialogId, dialogContentId, backstage, ariaAttrs));
  29263. const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
  29264. const objOfCells = extractCellsToObject(storagedMenuButtons);
  29265. const optMemFooter = someIf(storagedMenuButtons.length !== 0, record(renderInlineFooter({ buttons: storagedMenuButtons }, dialogId, backstage)));
  29266. const dialogEvents = initDialog(() => instanceApi, {
  29267. onBlock: event => {
  29268. Blocking.block(dialog, (_comp, bs) => {
  29269. const headerHeight = memHeader.getOpt(dialog).map(dialog => get$d(dialog.element));
  29270. return getBusySpec(event.message, bs, backstage.shared.providers, headerHeight);
  29271. });
  29272. },
  29273. onUnblock: () => {
  29274. Blocking.unblock(dialog);
  29275. },
  29276. onClose: () => extra.closeWindow()
  29277. }, backstage.shared.getSink);
  29278. const inlineClass = 'tox-dialog-inline';
  29279. const dialog = build$1({
  29280. dom: {
  29281. tag: 'div',
  29282. classes: [
  29283. 'tox-dialog',
  29284. inlineClass,
  29285. ...dialogSizeClass
  29286. ],
  29287. attributes: {
  29288. role: 'dialog',
  29289. ['aria-labelledby']: dialogLabelId
  29290. }
  29291. },
  29292. eventOrder: {
  29293. [receive()]: [
  29294. Reflecting.name(),
  29295. Receiving.name()
  29296. ],
  29297. [execute$5()]: ['execute-on-form'],
  29298. [attachedToDom()]: [
  29299. 'reflecting',
  29300. 'execute-on-form'
  29301. ]
  29302. },
  29303. behaviours: derive$1([
  29304. Keying.config({
  29305. mode: 'cyclic',
  29306. onEscape: c => {
  29307. emit(c, formCloseEvent);
  29308. return Optional.some(true);
  29309. },
  29310. useTabstopAt: elem => !isPseudoStop(elem) && (name$3(elem) !== 'button' || get$f(elem, 'disabled') !== 'disabled'),
  29311. firstTabstop: 1
  29312. }),
  29313. Reflecting.config({
  29314. channel: `${ dialogChannel }-${ dialogId }`,
  29315. updateState,
  29316. initialData: dialogInit
  29317. }),
  29318. Focusing.config({}),
  29319. config('execute-on-form', dialogEvents.concat([
  29320. runOnSource(focusin(), (comp, _se) => {
  29321. Keying.focusIn(comp);
  29322. }),
  29323. run$1(focusShifted(), (comp, se) => {
  29324. comp.getSystem().broadcastOn([dialogFocusShiftedChannel], { newFocus: se.event.newFocus });
  29325. })
  29326. ])),
  29327. Blocking.config({ getRoot: () => Optional.some(dialog) }),
  29328. Replacing.config({}),
  29329. memory({})
  29330. ]),
  29331. components: [
  29332. memHeader.asSpec(),
  29333. memBody.asSpec(),
  29334. ...optMemFooter.map(memFooter => memFooter.asSpec()).toArray()
  29335. ]
  29336. });
  29337. const toggleFullscreen$1 = () => {
  29338. toggleFullscreen(dialog, dialogSize.get());
  29339. };
  29340. const instanceApi = getDialogApi({
  29341. getId: constant$1(dialogId),
  29342. getRoot: constant$1(dialog),
  29343. getFooter: () => optMemFooter.map(memFooter => memFooter.get(dialog)),
  29344. getBody: () => memBody.get(dialog),
  29345. getFormWrapper: () => {
  29346. const body = memBody.get(dialog);
  29347. return Composing.getCurrent(body).getOr(body);
  29348. },
  29349. toggleFullscreen: toggleFullscreen$1
  29350. }, extra.redial, objOfCells);
  29351. return {
  29352. dialog,
  29353. instanceApi
  29354. };
  29355. };
  29356. var global = tinymce.util.Tools.resolve('tinymce.util.URI');
  29357. const getUrlDialogApi = root => {
  29358. const withRoot = f => {
  29359. if (root.getSystem().isConnected()) {
  29360. f(root);
  29361. }
  29362. };
  29363. const block = message => {
  29364. if (!isString(message)) {
  29365. throw new Error('The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
  29366. }
  29367. withRoot(root => {
  29368. emitWith(root, formBlockEvent, { message });
  29369. });
  29370. };
  29371. const unblock = () => {
  29372. withRoot(root => {
  29373. emit(root, formUnblockEvent);
  29374. });
  29375. };
  29376. const close = () => {
  29377. withRoot(root => {
  29378. emit(root, formCloseEvent);
  29379. });
  29380. };
  29381. const sendMessage = data => {
  29382. withRoot(root => {
  29383. root.getSystem().broadcastOn([bodySendMessageChannel], data);
  29384. });
  29385. };
  29386. return {
  29387. block,
  29388. unblock,
  29389. close,
  29390. sendMessage
  29391. };
  29392. };
  29393. const SUPPORTED_MESSAGE_ACTIONS = [
  29394. 'insertContent',
  29395. 'setContent',
  29396. 'execCommand',
  29397. 'close',
  29398. 'block',
  29399. 'unblock'
  29400. ];
  29401. const isSupportedMessage = data => isObject(data) && SUPPORTED_MESSAGE_ACTIONS.indexOf(data.mceAction) !== -1;
  29402. const isCustomMessage = data => !isSupportedMessage(data) && isObject(data) && has$2(data, 'mceAction');
  29403. const handleMessage = (editor, api, data) => {
  29404. switch (data.mceAction) {
  29405. case 'insertContent':
  29406. editor.insertContent(data.content);
  29407. break;
  29408. case 'setContent':
  29409. editor.setContent(data.content);
  29410. break;
  29411. case 'execCommand':
  29412. const ui = isBoolean(data.ui) ? data.ui : false;
  29413. editor.execCommand(data.cmd, ui, data.value);
  29414. break;
  29415. case 'close':
  29416. api.close();
  29417. break;
  29418. case 'block':
  29419. api.block(data.message);
  29420. break;
  29421. case 'unblock':
  29422. api.unblock();
  29423. break;
  29424. }
  29425. };
  29426. const renderUrlDialog = (internalDialog, extra, editor, backstage) => {
  29427. const dialogId = generate$6('dialog');
  29428. const header = getHeader(internalDialog.title, dialogId, backstage);
  29429. const body = renderIframeBody(internalDialog);
  29430. const footer = internalDialog.buttons.bind(buttons => {
  29431. if (buttons.length === 0) {
  29432. return Optional.none();
  29433. } else {
  29434. return Optional.some(renderModalFooter({ buttons }, dialogId, backstage));
  29435. }
  29436. });
  29437. const dialogEvents = initUrlDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra));
  29438. const styles = {
  29439. ...internalDialog.height.fold(() => ({}), height => ({
  29440. 'height': height + 'px',
  29441. 'max-height': height + 'px'
  29442. })),
  29443. ...internalDialog.width.fold(() => ({}), width => ({
  29444. 'width': width + 'px',
  29445. 'max-width': width + 'px'
  29446. }))
  29447. };
  29448. const classes = internalDialog.width.isNone() && internalDialog.height.isNone() ? ['tox-dialog--width-lg'] : [];
  29449. const iframeUri = new global(internalDialog.url, { base_uri: new global(window.location.href) });
  29450. const iframeDomain = `${ iframeUri.protocol }://${ iframeUri.host }${ iframeUri.port ? ':' + iframeUri.port : '' }`;
  29451. const messageHandlerUnbinder = unbindable();
  29452. const updateState = (_comp, incoming) => Optional.some(incoming);
  29453. const extraBehaviours = [
  29454. Reflecting.config({
  29455. channel: `${ dialogChannel }-${ dialogId }`,
  29456. updateState,
  29457. initialData: internalDialog
  29458. }),
  29459. config('messages', [
  29460. runOnAttached(() => {
  29461. const unbind = bind(SugarElement.fromDom(window), 'message', e => {
  29462. if (iframeUri.isSameOrigin(new global(e.raw.origin))) {
  29463. const data = e.raw.data;
  29464. if (isSupportedMessage(data)) {
  29465. handleMessage(editor, instanceApi, data);
  29466. } else if (isCustomMessage(data)) {
  29467. internalDialog.onMessage(instanceApi, data);
  29468. }
  29469. }
  29470. });
  29471. messageHandlerUnbinder.set(unbind);
  29472. }),
  29473. runOnDetached(messageHandlerUnbinder.clear)
  29474. ]),
  29475. Receiving.config({
  29476. channels: {
  29477. [bodySendMessageChannel]: {
  29478. onReceive: (comp, data) => {
  29479. descendant(comp.element, 'iframe').each(iframeEle => {
  29480. const iframeWin = iframeEle.dom.contentWindow;
  29481. if (isNonNullable(iframeWin)) {
  29482. iframeWin.postMessage(data, iframeDomain);
  29483. }
  29484. });
  29485. }
  29486. }
  29487. }
  29488. })
  29489. ];
  29490. const spec = {
  29491. id: dialogId,
  29492. header,
  29493. body,
  29494. footer,
  29495. extraClasses: classes,
  29496. extraBehaviours,
  29497. extraStyles: styles
  29498. };
  29499. const dialog = renderModalDialog(spec, dialogEvents, backstage);
  29500. const instanceApi = getUrlDialogApi(dialog);
  29501. return {
  29502. dialog,
  29503. instanceApi
  29504. };
  29505. };
  29506. const setup$2 = backstage => {
  29507. const sharedBackstage = backstage.shared;
  29508. const open = (message, callback) => {
  29509. const closeDialog = () => {
  29510. ModalDialog.hide(alertDialog);
  29511. callback();
  29512. };
  29513. const memFooterClose = record(renderFooterButton({
  29514. name: 'close-alert',
  29515. text: 'OK',
  29516. primary: true,
  29517. buttonType: Optional.some('primary'),
  29518. align: 'end',
  29519. enabled: true,
  29520. icon: Optional.none()
  29521. }, 'cancel', backstage));
  29522. const titleSpec = pUntitled();
  29523. const closeSpec = pClose(closeDialog, sharedBackstage.providers);
  29524. const alertDialog = build$1(renderDialog$1({
  29525. lazySink: () => sharedBackstage.getSink(),
  29526. header: hiddenHeader(titleSpec, closeSpec),
  29527. body: pBodyMessage(message, sharedBackstage.providers),
  29528. footer: Optional.some(pFooter(pFooterGroup([], [memFooterClose.asSpec()]))),
  29529. onEscape: closeDialog,
  29530. extraClasses: ['tox-alert-dialog'],
  29531. extraBehaviours: [],
  29532. extraStyles: {},
  29533. dialogEvents: [run$1(formCancelEvent, closeDialog)],
  29534. eventOrder: {}
  29535. }));
  29536. ModalDialog.show(alertDialog);
  29537. const footerCloseButton = memFooterClose.get(alertDialog);
  29538. Focusing.focus(footerCloseButton);
  29539. };
  29540. return { open };
  29541. };
  29542. const setup$1 = backstage => {
  29543. const sharedBackstage = backstage.shared;
  29544. const open = (message, callback) => {
  29545. const closeDialog = state => {
  29546. ModalDialog.hide(confirmDialog);
  29547. callback(state);
  29548. };
  29549. const memFooterYes = record(renderFooterButton({
  29550. name: 'yes',
  29551. text: 'Yes',
  29552. primary: true,
  29553. buttonType: Optional.some('primary'),
  29554. align: 'end',
  29555. enabled: true,
  29556. icon: Optional.none()
  29557. }, 'submit', backstage));
  29558. const footerNo = renderFooterButton({
  29559. name: 'no',
  29560. text: 'No',
  29561. primary: false,
  29562. buttonType: Optional.some('secondary'),
  29563. align: 'end',
  29564. enabled: true,
  29565. icon: Optional.none()
  29566. }, 'cancel', backstage);
  29567. const titleSpec = pUntitled();
  29568. const closeSpec = pClose(() => closeDialog(false), sharedBackstage.providers);
  29569. const confirmDialog = build$1(renderDialog$1({
  29570. lazySink: () => sharedBackstage.getSink(),
  29571. header: hiddenHeader(titleSpec, closeSpec),
  29572. body: pBodyMessage(message, sharedBackstage.providers),
  29573. footer: Optional.some(pFooter(pFooterGroup([], [
  29574. footerNo,
  29575. memFooterYes.asSpec()
  29576. ]))),
  29577. onEscape: () => closeDialog(false),
  29578. extraClasses: ['tox-confirm-dialog'],
  29579. extraBehaviours: [],
  29580. extraStyles: {},
  29581. dialogEvents: [
  29582. run$1(formCancelEvent, () => closeDialog(false)),
  29583. run$1(formSubmitEvent, () => closeDialog(true))
  29584. ],
  29585. eventOrder: {}
  29586. }));
  29587. ModalDialog.show(confirmDialog);
  29588. const footerYesButton = memFooterYes.get(confirmDialog);
  29589. Focusing.focus(footerYesButton);
  29590. };
  29591. return { open };
  29592. };
  29593. const validateData = (data, validator) => getOrDie(asRaw('data', validator, data));
  29594. const isAlertOrConfirmDialog = target => closest(target, '.tox-alert-dialog') || closest(target, '.tox-confirm-dialog');
  29595. const inlineAdditionalBehaviours = (editor, isStickyToolbar, isToolbarLocationTop) => {
  29596. if (isStickyToolbar && isToolbarLocationTop) {
  29597. return [];
  29598. } else {
  29599. return [Docking.config({
  29600. contextual: {
  29601. lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
  29602. fadeInClass: 'tox-dialog-dock-fadein',
  29603. fadeOutClass: 'tox-dialog-dock-fadeout',
  29604. transitionClass: 'tox-dialog-dock-transition'
  29605. },
  29606. modes: ['top'],
  29607. lazyViewport: comp => {
  29608. const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
  29609. return optScrollingContext.map(sc => {
  29610. const combinedBounds = getBoundsFrom(sc);
  29611. return {
  29612. bounds: combinedBounds,
  29613. optScrollEnv: Optional.some({
  29614. currentScrollTop: sc.element.dom.scrollTop,
  29615. scrollElmTop: absolute$3(sc.element).top
  29616. })
  29617. };
  29618. }).getOrThunk(() => ({
  29619. bounds: win(),
  29620. optScrollEnv: Optional.none()
  29621. }));
  29622. }
  29623. })];
  29624. }
  29625. };
  29626. const setup = extras => {
  29627. const editor = extras.editor;
  29628. const isStickyToolbar$1 = isStickyToolbar(editor);
  29629. const alertDialog = setup$2(extras.backstages.dialog);
  29630. const confirmDialog = setup$1(extras.backstages.dialog);
  29631. const open = (config, params, closeWindow) => {
  29632. if (!isUndefined(params)) {
  29633. if (params.inline === 'toolbar') {
  29634. return openInlineDialog(config, extras.backstages.popup.shared.anchors.inlineDialog(), closeWindow, params);
  29635. } else if (params.inline === 'bottom') {
  29636. return openBottomInlineDialog(config, extras.backstages.popup.shared.anchors.inlineBottomDialog(), closeWindow, params);
  29637. } else if (params.inline === 'cursor') {
  29638. return openInlineDialog(config, extras.backstages.popup.shared.anchors.cursor(), closeWindow, params);
  29639. }
  29640. }
  29641. return openModalDialog(config, closeWindow);
  29642. };
  29643. const openUrl = (config, closeWindow) => openModalUrlDialog(config, closeWindow);
  29644. const openModalUrlDialog = (config, closeWindow) => {
  29645. const factory = contents => {
  29646. const dialog = renderUrlDialog(contents, {
  29647. closeWindow: () => {
  29648. ModalDialog.hide(dialog.dialog);
  29649. closeWindow(dialog.instanceApi);
  29650. }
  29651. }, editor, extras.backstages.dialog);
  29652. ModalDialog.show(dialog.dialog);
  29653. return dialog.instanceApi;
  29654. };
  29655. return DialogManager.openUrl(factory, config);
  29656. };
  29657. const openModalDialog = (config, closeWindow) => {
  29658. const factory = (contents, internalInitialData, dataValidator) => {
  29659. const initialData = internalInitialData;
  29660. const dialogInit = {
  29661. dataValidator,
  29662. initialData,
  29663. internalDialog: contents
  29664. };
  29665. const dialog = renderDialog(dialogInit, {
  29666. redial: DialogManager.redial,
  29667. closeWindow: () => {
  29668. ModalDialog.hide(dialog.dialog);
  29669. closeWindow(dialog.instanceApi);
  29670. }
  29671. }, extras.backstages.dialog);
  29672. ModalDialog.show(dialog.dialog);
  29673. dialog.instanceApi.setData(initialData);
  29674. return dialog.instanceApi;
  29675. };
  29676. return DialogManager.open(factory, config);
  29677. };
  29678. const openInlineDialog = (config$1, anchor, closeWindow, windowParams) => {
  29679. const factory = (contents, internalInitialData, dataValidator) => {
  29680. const initialData = validateData(internalInitialData, dataValidator);
  29681. const inlineDialog = value$2();
  29682. const isToolbarLocationTop = extras.backstages.popup.shared.header.isPositionedAtTop();
  29683. const dialogInit = {
  29684. dataValidator,
  29685. initialData,
  29686. internalDialog: contents
  29687. };
  29688. const refreshDocking = () => inlineDialog.on(dialog => {
  29689. InlineView.reposition(dialog);
  29690. if (!isStickyToolbar$1 || !isToolbarLocationTop) {
  29691. Docking.refresh(dialog);
  29692. }
  29693. });
  29694. const dialogUi = renderInlineDialog(dialogInit, {
  29695. redial: DialogManager.redial,
  29696. closeWindow: () => {
  29697. inlineDialog.on(InlineView.hide);
  29698. editor.off('ResizeEditor', refreshDocking);
  29699. inlineDialog.clear();
  29700. closeWindow(dialogUi.instanceApi);
  29701. }
  29702. }, extras.backstages.popup, windowParams.ariaAttrs, refreshDocking);
  29703. const inlineDialogComp = build$1(InlineView.sketch({
  29704. lazySink: extras.backstages.popup.shared.getSink,
  29705. dom: {
  29706. tag: 'div',
  29707. classes: []
  29708. },
  29709. fireDismissalEventInstead: windowParams.persistent ? { event: 'doNotDismissYet' } : {},
  29710. ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
  29711. inlineBehaviours: derive$1([
  29712. config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
  29713. emit(dialogUi.dialog, formCancelEvent);
  29714. })]),
  29715. ...inlineAdditionalBehaviours(editor, isStickyToolbar$1, isToolbarLocationTop)
  29716. ]),
  29717. isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
  29718. }));
  29719. inlineDialog.set(inlineDialogComp);
  29720. const getInlineDialogBounds = () => {
  29721. const elem = editor.inline ? body() : SugarElement.fromDom(editor.getContainer());
  29722. const bounds = box$1(elem);
  29723. return Optional.some(bounds);
  29724. };
  29725. InlineView.showWithinBounds(inlineDialogComp, premade(dialogUi.dialog), { anchor }, getInlineDialogBounds);
  29726. if (!isStickyToolbar$1 || !isToolbarLocationTop) {
  29727. Docking.refresh(inlineDialogComp);
  29728. editor.on('ResizeEditor', refreshDocking);
  29729. }
  29730. dialogUi.instanceApi.setData(initialData);
  29731. Keying.focusIn(dialogUi.dialog);
  29732. return dialogUi.instanceApi;
  29733. };
  29734. return DialogManager.open(factory, config$1);
  29735. };
  29736. const openBottomInlineDialog = (config$1, anchor, closeWindow, windowParams) => {
  29737. const factory = (contents, internalInitialData, dataValidator) => {
  29738. const initialData = validateData(internalInitialData, dataValidator);
  29739. const inlineDialog = value$2();
  29740. const isToolbarLocationTop = extras.backstages.popup.shared.header.isPositionedAtTop();
  29741. const dialogInit = {
  29742. dataValidator,
  29743. initialData,
  29744. internalDialog: contents
  29745. };
  29746. const refreshDocking = () => inlineDialog.on(dialog => {
  29747. InlineView.reposition(dialog);
  29748. Docking.refresh(dialog);
  29749. });
  29750. const dialogUi = renderInlineDialog(dialogInit, {
  29751. redial: DialogManager.redial,
  29752. closeWindow: () => {
  29753. inlineDialog.on(InlineView.hide);
  29754. editor.off('ResizeEditor ScrollWindow ElementScroll', refreshDocking);
  29755. inlineDialog.clear();
  29756. closeWindow(dialogUi.instanceApi);
  29757. }
  29758. }, extras.backstages.popup, windowParams.ariaAttrs, refreshDocking);
  29759. const inlineDialogComp = build$1(InlineView.sketch({
  29760. lazySink: extras.backstages.popup.shared.getSink,
  29761. dom: {
  29762. tag: 'div',
  29763. classes: []
  29764. },
  29765. fireDismissalEventInstead: windowParams.persistent ? { event: 'doNotDismissYet' } : {},
  29766. ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
  29767. inlineBehaviours: derive$1([
  29768. config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
  29769. emit(dialogUi.dialog, formCancelEvent);
  29770. })]),
  29771. Docking.config({
  29772. contextual: {
  29773. lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
  29774. fadeInClass: 'tox-dialog-dock-fadein',
  29775. fadeOutClass: 'tox-dialog-dock-fadeout',
  29776. transitionClass: 'tox-dialog-dock-transition'
  29777. },
  29778. modes: [
  29779. 'top',
  29780. 'bottom'
  29781. ],
  29782. lazyViewport: comp => {
  29783. const optScrollingContext = detectWhenSplitUiMode(editor, comp.element);
  29784. return optScrollingContext.map(sc => {
  29785. const combinedBounds = getBoundsFrom(sc);
  29786. return {
  29787. bounds: combinedBounds,
  29788. optScrollEnv: Optional.some({
  29789. currentScrollTop: sc.element.dom.scrollTop,
  29790. scrollElmTop: absolute$3(sc.element).top
  29791. })
  29792. };
  29793. }).getOrThunk(() => ({
  29794. bounds: win(),
  29795. optScrollEnv: Optional.none()
  29796. }));
  29797. }
  29798. })
  29799. ]),
  29800. isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
  29801. }));
  29802. inlineDialog.set(inlineDialogComp);
  29803. const getInlineDialogBounds = () => {
  29804. return extras.backstages.popup.shared.getSink().toOptional().bind(s => {
  29805. const optScrollingContext = detectWhenSplitUiMode(editor, s.element);
  29806. const margin = 15;
  29807. const bounds$1 = optScrollingContext.map(sc => getBoundsFrom(sc)).getOr(win());
  29808. const contentAreaContainer = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
  29809. const constrainedBounds = constrain(contentAreaContainer, bounds$1);
  29810. return Optional.some(bounds(constrainedBounds.x, constrainedBounds.y, constrainedBounds.width, constrainedBounds.height - margin));
  29811. });
  29812. };
  29813. InlineView.showWithinBounds(inlineDialogComp, premade(dialogUi.dialog), { anchor }, getInlineDialogBounds);
  29814. Docking.refresh(inlineDialogComp);
  29815. editor.on('ResizeEditor ScrollWindow ElementScroll ResizeWindow', refreshDocking);
  29816. dialogUi.instanceApi.setData(initialData);
  29817. Keying.focusIn(dialogUi.dialog);
  29818. return dialogUi.instanceApi;
  29819. };
  29820. return DialogManager.open(factory, config$1);
  29821. };
  29822. const confirm = (message, callback) => {
  29823. confirmDialog.open(message, callback);
  29824. };
  29825. const alert = (message, callback) => {
  29826. alertDialog.open(message, callback);
  29827. };
  29828. const close = instanceApi => {
  29829. instanceApi.close();
  29830. };
  29831. return {
  29832. open,
  29833. openUrl,
  29834. alert,
  29835. close,
  29836. confirm
  29837. };
  29838. };
  29839. const registerOptions = editor => {
  29840. register$e(editor);
  29841. register$d(editor);
  29842. register(editor);
  29843. };
  29844. var Theme = () => {
  29845. global$a.add('silver', editor => {
  29846. registerOptions(editor);
  29847. let popupSinkBounds = () => win();
  29848. const {
  29849. dialogs,
  29850. popups,
  29851. renderUI: renderModeUI
  29852. } = setup$3(editor, { getPopupSinkBounds: () => popupSinkBounds() });
  29853. const renderUI = () => {
  29854. const renderResult = renderModeUI();
  29855. const optScrollingContext = detectWhenSplitUiMode(editor, popups.getMothership().element);
  29856. optScrollingContext.each(sc => {
  29857. popupSinkBounds = () => {
  29858. return getBoundsFrom(sc);
  29859. };
  29860. });
  29861. return renderResult;
  29862. };
  29863. Autocompleter.register(editor, popups.backstage.shared);
  29864. const windowMgr = setup({
  29865. editor,
  29866. backstages: {
  29867. popup: popups.backstage,
  29868. dialog: dialogs.backstage
  29869. }
  29870. });
  29871. const getNotificationManagerImpl = () => NotificationManagerImpl(editor, { backstage: popups.backstage }, popups.getMothership());
  29872. return {
  29873. renderUI,
  29874. getWindowManagerImpl: constant$1(windowMgr),
  29875. getNotificationManagerImpl
  29876. };
  29877. });
  29878. };
  29879. Theme();
  29880. })();