theme.js 909 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183
  1. /**
  2. * TinyMCE version 6.1.0 (2022-06-29)
  3. */
  4. (function () {
  5. 'use strict';
  6. const getPrototypeOf = 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(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 = f => {
  86. return f();
  87. };
  88. const never = constant$1(false);
  89. const always = constant$1(true);
  90. var global$a = tinymce.util.Tools.resolve('tinymce.ThemeManager');
  91. class Optional {
  92. constructor(tag, value) {
  93. this.tag = tag;
  94. this.value = value;
  95. }
  96. static some(value) {
  97. return new Optional(true, value);
  98. }
  99. static none() {
  100. return Optional.singletonNone;
  101. }
  102. fold(onNone, onSome) {
  103. if (this.tag) {
  104. return onSome(this.value);
  105. } else {
  106. return onNone();
  107. }
  108. }
  109. isSome() {
  110. return this.tag;
  111. }
  112. isNone() {
  113. return !this.tag;
  114. }
  115. map(mapper) {
  116. if (this.tag) {
  117. return Optional.some(mapper(this.value));
  118. } else {
  119. return Optional.none();
  120. }
  121. }
  122. bind(binder) {
  123. if (this.tag) {
  124. return binder(this.value);
  125. } else {
  126. return Optional.none();
  127. }
  128. }
  129. exists(predicate) {
  130. return this.tag && predicate(this.value);
  131. }
  132. forall(predicate) {
  133. return !this.tag || predicate(this.value);
  134. }
  135. filter(predicate) {
  136. if (!this.tag || predicate(this.value)) {
  137. return this;
  138. } else {
  139. return Optional.none();
  140. }
  141. }
  142. getOr(replacement) {
  143. return this.tag ? this.value : replacement;
  144. }
  145. or(replacement) {
  146. return this.tag ? this : replacement;
  147. }
  148. getOrThunk(thunk) {
  149. return this.tag ? this.value : thunk();
  150. }
  151. orThunk(thunk) {
  152. return this.tag ? this : thunk();
  153. }
  154. getOrDie(message) {
  155. if (!this.tag) {
  156. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  157. } else {
  158. return this.value;
  159. }
  160. }
  161. static from(value) {
  162. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  163. }
  164. getOrNull() {
  165. return this.tag ? this.value : null;
  166. }
  167. getOrUndefined() {
  168. return this.value;
  169. }
  170. each(worker) {
  171. if (this.tag) {
  172. worker(this.value);
  173. }
  174. }
  175. toArray() {
  176. return this.tag ? [this.value] : [];
  177. }
  178. toString() {
  179. return this.tag ? `some(${ this.value })` : 'none()';
  180. }
  181. }
  182. Optional.singletonNone = new Optional(false);
  183. const nativeSlice = Array.prototype.slice;
  184. const nativeIndexOf = Array.prototype.indexOf;
  185. const nativePush = Array.prototype.push;
  186. const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  187. const indexOf = (xs, x) => {
  188. const r = rawIndexOf(xs, x);
  189. return r === -1 ? Optional.none() : Optional.some(r);
  190. };
  191. const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
  192. const exists = (xs, pred) => {
  193. for (let i = 0, len = xs.length; i < len; i++) {
  194. const x = xs[i];
  195. if (pred(x, i)) {
  196. return true;
  197. }
  198. }
  199. return false;
  200. };
  201. const range$2 = (num, f) => {
  202. const r = [];
  203. for (let i = 0; i < num; i++) {
  204. r.push(f(i));
  205. }
  206. return r;
  207. };
  208. const chunk$1 = (array, size) => {
  209. const r = [];
  210. for (let i = 0; i < array.length; i += size) {
  211. const s = nativeSlice.call(array, i, i + size);
  212. r.push(s);
  213. }
  214. return r;
  215. };
  216. const map$2 = (xs, f) => {
  217. const len = xs.length;
  218. const r = new Array(len);
  219. for (let i = 0; i < len; i++) {
  220. const x = xs[i];
  221. r[i] = f(x, i);
  222. }
  223. return r;
  224. };
  225. const each$1 = (xs, f) => {
  226. for (let i = 0, len = xs.length; i < len; i++) {
  227. const x = xs[i];
  228. f(x, i);
  229. }
  230. };
  231. const eachr = (xs, f) => {
  232. for (let i = xs.length - 1; i >= 0; i--) {
  233. const x = xs[i];
  234. f(x, i);
  235. }
  236. };
  237. const partition$3 = (xs, pred) => {
  238. const pass = [];
  239. const fail = [];
  240. for (let i = 0, len = xs.length; i < len; i++) {
  241. const x = xs[i];
  242. const arr = pred(x, i) ? pass : fail;
  243. arr.push(x);
  244. }
  245. return {
  246. pass,
  247. fail
  248. };
  249. };
  250. const filter$2 = (xs, pred) => {
  251. const r = [];
  252. for (let i = 0, len = xs.length; i < len; i++) {
  253. const x = xs[i];
  254. if (pred(x, i)) {
  255. r.push(x);
  256. }
  257. }
  258. return r;
  259. };
  260. const foldr = (xs, f, acc) => {
  261. eachr(xs, (x, i) => {
  262. acc = f(acc, x, i);
  263. });
  264. return acc;
  265. };
  266. const foldl = (xs, f, acc) => {
  267. each$1(xs, (x, i) => {
  268. acc = f(acc, x, i);
  269. });
  270. return acc;
  271. };
  272. const findUntil = (xs, pred, until) => {
  273. for (let i = 0, len = xs.length; i < len; i++) {
  274. const x = xs[i];
  275. if (pred(x, i)) {
  276. return Optional.some(x);
  277. } else if (until(x, i)) {
  278. break;
  279. }
  280. }
  281. return Optional.none();
  282. };
  283. const find$5 = (xs, pred) => {
  284. return findUntil(xs, pred, never);
  285. };
  286. const findIndex$1 = (xs, pred) => {
  287. for (let i = 0, len = xs.length; i < len; i++) {
  288. const x = xs[i];
  289. if (pred(x, i)) {
  290. return Optional.some(i);
  291. }
  292. }
  293. return Optional.none();
  294. };
  295. const flatten = xs => {
  296. const r = [];
  297. for (let i = 0, len = xs.length; i < len; ++i) {
  298. if (!isArray(xs[i])) {
  299. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  300. }
  301. nativePush.apply(r, xs[i]);
  302. }
  303. return r;
  304. };
  305. const bind$3 = (xs, f) => flatten(map$2(xs, f));
  306. const forall = (xs, pred) => {
  307. for (let i = 0, len = xs.length; i < len; ++i) {
  308. const x = xs[i];
  309. if (pred(x, i) !== true) {
  310. return false;
  311. }
  312. }
  313. return true;
  314. };
  315. const reverse = xs => {
  316. const r = nativeSlice.call(xs, 0);
  317. r.reverse();
  318. return r;
  319. };
  320. const difference = (a1, a2) => filter$2(a1, x => !contains$2(a2, x));
  321. const mapToObject = (xs, f) => {
  322. const r = {};
  323. for (let i = 0, len = xs.length; i < len; i++) {
  324. const x = xs[i];
  325. r[String(x)] = f(x, i);
  326. }
  327. return r;
  328. };
  329. const pure$2 = x => [x];
  330. const sort = (xs, comparator) => {
  331. const copy = nativeSlice.call(xs, 0);
  332. copy.sort(comparator);
  333. return copy;
  334. };
  335. const get$h = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  336. const head = xs => get$h(xs, 0);
  337. const last$1 = xs => get$h(xs, xs.length - 1);
  338. const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
  339. const findMap = (arr, f) => {
  340. for (let i = 0; i < arr.length; i++) {
  341. const r = f(arr[i], i);
  342. if (r.isSome()) {
  343. return r;
  344. }
  345. }
  346. return Optional.none();
  347. };
  348. const keys = Object.keys;
  349. const hasOwnProperty = Object.hasOwnProperty;
  350. const each = (obj, f) => {
  351. const props = keys(obj);
  352. for (let k = 0, len = props.length; k < len; k++) {
  353. const i = props[k];
  354. const x = obj[i];
  355. f(x, i);
  356. }
  357. };
  358. const map$1 = (obj, f) => {
  359. return tupleMap(obj, (x, i) => ({
  360. k: i,
  361. v: f(x, i)
  362. }));
  363. };
  364. const tupleMap = (obj, f) => {
  365. const r = {};
  366. each(obj, (x, i) => {
  367. const tuple = f(x, i);
  368. r[tuple.k] = tuple.v;
  369. });
  370. return r;
  371. };
  372. const objAcc = r => (x, i) => {
  373. r[i] = x;
  374. };
  375. const internalFilter = (obj, pred, onTrue, onFalse) => {
  376. const r = {};
  377. each(obj, (x, i) => {
  378. (pred(x, i) ? onTrue : onFalse)(x, i);
  379. });
  380. return r;
  381. };
  382. const bifilter = (obj, pred) => {
  383. const t = {};
  384. const f = {};
  385. internalFilter(obj, pred, objAcc(t), objAcc(f));
  386. return {
  387. t,
  388. f
  389. };
  390. };
  391. const filter$1 = (obj, pred) => {
  392. const t = {};
  393. internalFilter(obj, pred, objAcc(t), noop);
  394. return t;
  395. };
  396. const mapToArray = (obj, f) => {
  397. const r = [];
  398. each(obj, (value, name) => {
  399. r.push(f(value, name));
  400. });
  401. return r;
  402. };
  403. const find$4 = (obj, pred) => {
  404. const props = keys(obj);
  405. for (let k = 0, len = props.length; k < len; k++) {
  406. const i = props[k];
  407. const x = obj[i];
  408. if (pred(x, i, obj)) {
  409. return Optional.some(x);
  410. }
  411. }
  412. return Optional.none();
  413. };
  414. const values = obj => {
  415. return mapToArray(obj, identity);
  416. };
  417. const get$g = (obj, key) => {
  418. return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
  419. };
  420. const has$2 = (obj, key) => hasOwnProperty.call(obj, key);
  421. const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
  422. const is$1 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  423. const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
  424. const cat = arr => {
  425. const r = [];
  426. const push = x => {
  427. r.push(x);
  428. };
  429. for (let i = 0; i < arr.length; i++) {
  430. arr[i].each(push);
  431. }
  432. return r;
  433. };
  434. const sequence = arr => {
  435. const r = [];
  436. for (let i = 0; i < arr.length; i++) {
  437. const x = arr[i];
  438. if (x.isSome()) {
  439. r.push(x.getOrDie());
  440. } else {
  441. return Optional.none();
  442. }
  443. }
  444. return Optional.some(r);
  445. };
  446. const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  447. const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
  448. const mapFrom = (a, f) => a !== undefined && a !== null ? Optional.some(f(a)) : Optional.none();
  449. const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  450. const addToEnd = (str, suffix) => {
  451. return str + suffix;
  452. };
  453. const removeFromStart = (str, numChars) => {
  454. return str.substring(numChars);
  455. };
  456. const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  457. const removeLeading = (str, prefix) => {
  458. return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  459. };
  460. const ensureTrailing = (str, suffix) => {
  461. return endsWith(str, suffix) ? str : addToEnd(str, suffix);
  462. };
  463. const contains$1 = (str, substr) => {
  464. return str.indexOf(substr) !== -1;
  465. };
  466. const startsWith = (str, prefix) => {
  467. return checkRange(str, prefix, 0);
  468. };
  469. const endsWith = (str, suffix) => {
  470. return checkRange(str, suffix, str.length - suffix.length);
  471. };
  472. const blank = r => s => s.replace(r, '');
  473. const trim$1 = blank(/^\s+|\s+$/g);
  474. const isNotEmpty = s => s.length > 0;
  475. const isEmpty = s => !isNotEmpty(s);
  476. const isSupported$1 = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  477. const fromHtml$2 = (html, scope) => {
  478. const doc = scope || document;
  479. const div = doc.createElement('div');
  480. div.innerHTML = html;
  481. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  482. const message = 'HTML does not have a single root node';
  483. console.error(message, html);
  484. throw new Error(message);
  485. }
  486. return fromDom(div.childNodes[0]);
  487. };
  488. const fromTag = (tag, scope) => {
  489. const doc = scope || document;
  490. const node = doc.createElement(tag);
  491. return fromDom(node);
  492. };
  493. const fromText = (text, scope) => {
  494. const doc = scope || document;
  495. const node = doc.createTextNode(text);
  496. return fromDom(node);
  497. };
  498. const fromDom = node => {
  499. if (node === null || node === undefined) {
  500. throw new Error('Node cannot be null or undefined');
  501. }
  502. return { dom: node };
  503. };
  504. const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom);
  505. const SugarElement = {
  506. fromHtml: fromHtml$2,
  507. fromTag,
  508. fromText,
  509. fromDom,
  510. fromPoint
  511. };
  512. typeof window !== 'undefined' ? window : Function('return this;')();
  513. const DOCUMENT = 9;
  514. const DOCUMENT_FRAGMENT = 11;
  515. const ELEMENT = 1;
  516. const TEXT = 3;
  517. const name$3 = element => {
  518. const r = element.dom.nodeName;
  519. return r.toLowerCase();
  520. };
  521. const type$1 = element => element.dom.nodeType;
  522. const isType = t => element => type$1(element) === t;
  523. const isElement$1 = isType(ELEMENT);
  524. const isText = isType(TEXT);
  525. const isDocument = isType(DOCUMENT);
  526. const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  527. const isTag = tag => e => isElement$1(e) && name$3(e) === tag;
  528. const is = (element, selector) => {
  529. const dom = element.dom;
  530. if (dom.nodeType !== ELEMENT) {
  531. return false;
  532. } else {
  533. const elem = dom;
  534. if (elem.matches !== undefined) {
  535. return elem.matches(selector);
  536. } else if (elem.msMatchesSelector !== undefined) {
  537. return elem.msMatchesSelector(selector);
  538. } else if (elem.webkitMatchesSelector !== undefined) {
  539. return elem.webkitMatchesSelector(selector);
  540. } else if (elem.mozMatchesSelector !== undefined) {
  541. return elem.mozMatchesSelector(selector);
  542. } else {
  543. throw new Error('Browser lacks native selectors');
  544. }
  545. }
  546. };
  547. const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  548. const all$3 = (selector, scope) => {
  549. const base = scope === undefined ? document : scope.dom;
  550. return bypassSelector(base) ? [] : map$2(base.querySelectorAll(selector), SugarElement.fromDom);
  551. };
  552. const one = (selector, scope) => {
  553. const base = scope === undefined ? document : scope.dom;
  554. return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
  555. };
  556. const eq = (e1, e2) => e1.dom === e2.dom;
  557. const contains = (e1, e2) => {
  558. const d1 = e1.dom;
  559. const d2 = e2.dom;
  560. return d1 === d2 ? false : d1.contains(d2);
  561. };
  562. const owner$4 = element => SugarElement.fromDom(element.dom.ownerDocument);
  563. const documentOrOwner = dos => isDocument(dos) ? dos : owner$4(dos);
  564. const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
  565. const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
  566. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  567. const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
  568. const offsetParent = element => Optional.from(element.dom.offsetParent).map(SugarElement.fromDom);
  569. const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  570. const children = element => map$2(element.dom.childNodes, SugarElement.fromDom);
  571. const child$2 = (element, index) => {
  572. const cs = element.dom.childNodes;
  573. return Optional.from(cs[index]).map(SugarElement.fromDom);
  574. };
  575. const firstChild = element => child$2(element, 0);
  576. const spot = (element, offset) => ({
  577. element,
  578. offset
  579. });
  580. const leaf = (element, offset) => {
  581. const cs = children(element);
  582. return cs.length > 0 && offset < cs.length ? spot(cs[offset], 0) : spot(element, offset);
  583. };
  584. const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  585. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  586. const isSupported = constant$1(supported);
  587. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  588. const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
  589. const isInShadowRoot = e => getShadowRoot(e).isSome();
  590. const getShadowRoot = e => {
  591. const r = getRootNode(e);
  592. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  593. };
  594. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  595. const getOriginalEventTarget = event => {
  596. if (isSupported() && isNonNullable(event.target)) {
  597. const el = SugarElement.fromDom(event.target);
  598. if (isElement$1(el) && isOpenShadowHost(el)) {
  599. if (event.composed && event.composedPath) {
  600. const composedPath = event.composedPath();
  601. if (composedPath) {
  602. return head(composedPath);
  603. }
  604. }
  605. }
  606. }
  607. return Optional.from(event.target);
  608. };
  609. const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
  610. const inBody = element => {
  611. const dom = isText(element) ? element.dom.parentNode : element.dom;
  612. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  613. return false;
  614. }
  615. const doc = dom.ownerDocument;
  616. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  617. };
  618. const body = () => getBody(SugarElement.fromDom(document));
  619. const getBody = doc => {
  620. const b = doc.dom.body;
  621. if (b === null || b === undefined) {
  622. throw new Error('Body is not available yet');
  623. }
  624. return SugarElement.fromDom(b);
  625. };
  626. const rawSet = (dom, key, value) => {
  627. if (isString(value) || isBoolean(value) || isNumber(value)) {
  628. dom.setAttribute(key, value + '');
  629. } else {
  630. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  631. throw new Error('Attribute value was not simple');
  632. }
  633. };
  634. const set$9 = (element, key, value) => {
  635. rawSet(element.dom, key, value);
  636. };
  637. const setAll$1 = (element, attrs) => {
  638. const dom = element.dom;
  639. each(attrs, (v, k) => {
  640. rawSet(dom, k, v);
  641. });
  642. };
  643. const get$f = (element, key) => {
  644. const v = element.dom.getAttribute(key);
  645. return v === null ? undefined : v;
  646. };
  647. const getOpt = (element, key) => Optional.from(get$f(element, key));
  648. const has$1 = (element, key) => {
  649. const dom = element.dom;
  650. return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
  651. };
  652. const remove$7 = (element, key) => {
  653. element.dom.removeAttribute(key);
  654. };
  655. const clone$1 = element => foldl(element.dom.attributes, (acc, attr) => {
  656. acc[attr.name] = attr.value;
  657. return acc;
  658. }, {});
  659. const internalSet = (dom, property, value) => {
  660. if (!isString(value)) {
  661. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  662. throw new Error('CSS value must be a string: ' + value);
  663. }
  664. if (isSupported$1(dom)) {
  665. dom.style.setProperty(property, value);
  666. }
  667. };
  668. const internalRemove = (dom, property) => {
  669. if (isSupported$1(dom)) {
  670. dom.style.removeProperty(property);
  671. }
  672. };
  673. const set$8 = (element, property, value) => {
  674. const dom = element.dom;
  675. internalSet(dom, property, value);
  676. };
  677. const setAll = (element, css) => {
  678. const dom = element.dom;
  679. each(css, (v, k) => {
  680. internalSet(dom, k, v);
  681. });
  682. };
  683. const setOptions = (element, css) => {
  684. const dom = element.dom;
  685. each(css, (v, k) => {
  686. v.fold(() => {
  687. internalRemove(dom, k);
  688. }, value => {
  689. internalSet(dom, k, value);
  690. });
  691. });
  692. };
  693. const get$e = (element, property) => {
  694. const dom = element.dom;
  695. const styles = window.getComputedStyle(dom);
  696. const r = styles.getPropertyValue(property);
  697. return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  698. };
  699. const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : '';
  700. const getRaw = (element, property) => {
  701. const dom = element.dom;
  702. const raw = getUnsafeProperty(dom, property);
  703. return Optional.from(raw).filter(r => r.length > 0);
  704. };
  705. const getAllRaw = element => {
  706. const css = {};
  707. const dom = element.dom;
  708. if (isSupported$1(dom)) {
  709. for (let i = 0; i < dom.style.length; i++) {
  710. const ruleName = dom.style.item(i);
  711. css[ruleName] = dom.style[ruleName];
  712. }
  713. }
  714. return css;
  715. };
  716. const isValidValue = (tag, property, value) => {
  717. const element = SugarElement.fromTag(tag);
  718. set$8(element, property, value);
  719. const style = getRaw(element, property);
  720. return style.isSome();
  721. };
  722. const remove$6 = (element, property) => {
  723. const dom = element.dom;
  724. internalRemove(dom, property);
  725. if (is$1(getOpt(element, 'style').map(trim$1), '')) {
  726. remove$7(element, 'style');
  727. }
  728. };
  729. const reflow = e => e.dom.offsetWidth;
  730. const Dimension = (name, getOffset) => {
  731. const set = (element, h) => {
  732. if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
  733. throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
  734. }
  735. const dom = element.dom;
  736. if (isSupported$1(dom)) {
  737. dom.style[name] = h + 'px';
  738. }
  739. };
  740. const get = element => {
  741. const r = getOffset(element);
  742. if (r <= 0 || r === null) {
  743. const css = get$e(element, name);
  744. return parseFloat(css) || 0;
  745. }
  746. return r;
  747. };
  748. const getOuter = get;
  749. const aggregate = (element, properties) => foldl(properties, (acc, property) => {
  750. const val = get$e(element, property);
  751. const value = val === undefined ? 0 : parseInt(val, 10);
  752. return isNaN(value) ? acc : acc + value;
  753. }, 0);
  754. const max = (element, value, properties) => {
  755. const cumulativeInclusions = aggregate(element, properties);
  756. const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
  757. return absoluteMax;
  758. };
  759. return {
  760. set,
  761. get,
  762. getOuter,
  763. aggregate,
  764. max
  765. };
  766. };
  767. const api$2 = Dimension('height', element => {
  768. const dom = element.dom;
  769. return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
  770. });
  771. const get$d = element => api$2.get(element);
  772. const getOuter$2 = element => api$2.getOuter(element);
  773. const setMax$1 = (element, value) => {
  774. const inclusions = [
  775. 'margin-top',
  776. 'border-top-width',
  777. 'padding-top',
  778. 'padding-bottom',
  779. 'border-bottom-width',
  780. 'margin-bottom'
  781. ];
  782. const absMax = api$2.max(element, value, inclusions);
  783. set$8(element, 'max-height', absMax + 'px');
  784. };
  785. const r$1 = (left, top) => {
  786. const translate = (x, y) => r$1(left + x, top + y);
  787. return {
  788. left,
  789. top,
  790. translate
  791. };
  792. };
  793. const SugarPosition = r$1;
  794. const boxPosition = dom => {
  795. const box = dom.getBoundingClientRect();
  796. return SugarPosition(box.left, box.top);
  797. };
  798. const firstDefinedOrZero = (a, b) => {
  799. if (a !== undefined) {
  800. return a;
  801. } else {
  802. return b !== undefined ? b : 0;
  803. }
  804. };
  805. const absolute$3 = element => {
  806. const doc = element.dom.ownerDocument;
  807. const body = doc.body;
  808. const win = doc.defaultView;
  809. const html = doc.documentElement;
  810. if (body === element.dom) {
  811. return SugarPosition(body.offsetLeft, body.offsetTop);
  812. }
  813. const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
  814. const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
  815. const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
  816. const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
  817. return viewport$1(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
  818. };
  819. const viewport$1 = element => {
  820. const dom = element.dom;
  821. const doc = dom.ownerDocument;
  822. const body = doc.body;
  823. if (body === dom) {
  824. return SugarPosition(body.offsetLeft, body.offsetTop);
  825. }
  826. if (!inBody(element)) {
  827. return SugarPosition(0, 0);
  828. }
  829. return boxPosition(dom);
  830. };
  831. const api$1 = Dimension('width', element => element.dom.offsetWidth);
  832. const set$7 = (element, h) => api$1.set(element, h);
  833. const get$c = element => api$1.get(element);
  834. const getOuter$1 = element => api$1.getOuter(element);
  835. const setMax = (element, value) => {
  836. const inclusions = [
  837. 'margin-left',
  838. 'border-left-width',
  839. 'padding-left',
  840. 'padding-right',
  841. 'border-right-width',
  842. 'margin-right'
  843. ];
  844. const absMax = api$1.max(element, value, inclusions);
  845. set$8(element, 'max-width', absMax + 'px');
  846. };
  847. const cached = f => {
  848. let called = false;
  849. let r;
  850. return (...args) => {
  851. if (!called) {
  852. called = true;
  853. r = f.apply(null, args);
  854. }
  855. return r;
  856. };
  857. };
  858. const DeviceType = (os, browser, userAgent, mediaMatch) => {
  859. const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  860. const isiPhone = os.isiOS() && !isiPad;
  861. const isMobile = os.isiOS() || os.isAndroid();
  862. const isTouch = isMobile || mediaMatch('(pointer:coarse)');
  863. const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  864. const isPhone = isiPhone || isMobile && !isTablet;
  865. const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  866. const isDesktop = !isPhone && !isTablet && !iOSwebview;
  867. return {
  868. isiPad: constant$1(isiPad),
  869. isiPhone: constant$1(isiPhone),
  870. isTablet: constant$1(isTablet),
  871. isPhone: constant$1(isPhone),
  872. isTouch: constant$1(isTouch),
  873. isAndroid: os.isAndroid,
  874. isiOS: os.isiOS,
  875. isWebView: constant$1(iOSwebview),
  876. isDesktop: constant$1(isDesktop)
  877. };
  878. };
  879. const firstMatch = (regexes, s) => {
  880. for (let i = 0; i < regexes.length; i++) {
  881. const x = regexes[i];
  882. if (x.test(s)) {
  883. return x;
  884. }
  885. }
  886. return undefined;
  887. };
  888. const find$3 = (regexes, agent) => {
  889. const r = firstMatch(regexes, agent);
  890. if (!r) {
  891. return {
  892. major: 0,
  893. minor: 0
  894. };
  895. }
  896. const group = i => {
  897. return Number(agent.replace(r, '$' + i));
  898. };
  899. return nu$d(group(1), group(2));
  900. };
  901. const detect$4 = (versionRegexes, agent) => {
  902. const cleanedAgent = String(agent).toLowerCase();
  903. if (versionRegexes.length === 0) {
  904. return unknown$3();
  905. }
  906. return find$3(versionRegexes, cleanedAgent);
  907. };
  908. const unknown$3 = () => {
  909. return nu$d(0, 0);
  910. };
  911. const nu$d = (major, minor) => {
  912. return {
  913. major,
  914. minor
  915. };
  916. };
  917. const Version = {
  918. nu: nu$d,
  919. detect: detect$4,
  920. unknown: unknown$3
  921. };
  922. const detectBrowser$1 = (browsers, userAgentData) => {
  923. return findMap(userAgentData.brands, uaBrand => {
  924. const lcBrand = uaBrand.brand.toLowerCase();
  925. return find$5(browsers, browser => {
  926. var _a;
  927. return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
  928. }).map(info => ({
  929. current: info.name,
  930. version: Version.nu(parseInt(uaBrand.version, 10), 0)
  931. }));
  932. });
  933. };
  934. const detect$3 = (candidates, userAgent) => {
  935. const agent = String(userAgent).toLowerCase();
  936. return find$5(candidates, candidate => {
  937. return candidate.search(agent);
  938. });
  939. };
  940. const detectBrowser = (browsers, userAgent) => {
  941. return detect$3(browsers, userAgent).map(browser => {
  942. const version = Version.detect(browser.versionRegexes, userAgent);
  943. return {
  944. current: browser.name,
  945. version
  946. };
  947. });
  948. };
  949. const detectOs = (oses, userAgent) => {
  950. return detect$3(oses, userAgent).map(os => {
  951. const version = Version.detect(os.versionRegexes, userAgent);
  952. return {
  953. current: os.name,
  954. version
  955. };
  956. });
  957. };
  958. const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  959. const checkContains = target => {
  960. return uastring => {
  961. return contains$1(uastring, target);
  962. };
  963. };
  964. const browsers = [
  965. {
  966. name: 'Edge',
  967. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  968. search: uastring => {
  969. return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
  970. }
  971. },
  972. {
  973. name: 'Chromium',
  974. brand: 'Chromium',
  975. versionRegexes: [
  976. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  977. normalVersionRegex
  978. ],
  979. search: uastring => {
  980. return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
  981. }
  982. },
  983. {
  984. name: 'IE',
  985. versionRegexes: [
  986. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  987. /.*?rv:([0-9]+)\.([0-9]+).*/
  988. ],
  989. search: uastring => {
  990. return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
  991. }
  992. },
  993. {
  994. name: 'Opera',
  995. versionRegexes: [
  996. normalVersionRegex,
  997. /.*?opera\/([0-9]+)\.([0-9]+).*/
  998. ],
  999. search: checkContains('opera')
  1000. },
  1001. {
  1002. name: 'Firefox',
  1003. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  1004. search: checkContains('firefox')
  1005. },
  1006. {
  1007. name: 'Safari',
  1008. versionRegexes: [
  1009. normalVersionRegex,
  1010. /.*?cpu os ([0-9]+)_([0-9]+).*/
  1011. ],
  1012. search: uastring => {
  1013. return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
  1014. }
  1015. }
  1016. ];
  1017. const oses = [
  1018. {
  1019. name: 'Windows',
  1020. search: checkContains('win'),
  1021. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  1022. },
  1023. {
  1024. name: 'iOS',
  1025. search: uastring => {
  1026. return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
  1027. },
  1028. versionRegexes: [
  1029. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  1030. /.*cpu os ([0-9]+)_([0-9]+).*/,
  1031. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  1032. ]
  1033. },
  1034. {
  1035. name: 'Android',
  1036. search: checkContains('android'),
  1037. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  1038. },
  1039. {
  1040. name: 'macOS',
  1041. search: checkContains('mac os x'),
  1042. versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
  1043. },
  1044. {
  1045. name: 'Linux',
  1046. search: checkContains('linux'),
  1047. versionRegexes: []
  1048. },
  1049. {
  1050. name: 'Solaris',
  1051. search: checkContains('sunos'),
  1052. versionRegexes: []
  1053. },
  1054. {
  1055. name: 'FreeBSD',
  1056. search: checkContains('freebsd'),
  1057. versionRegexes: []
  1058. },
  1059. {
  1060. name: 'ChromeOS',
  1061. search: checkContains('cros'),
  1062. versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
  1063. }
  1064. ];
  1065. const PlatformInfo = {
  1066. browsers: constant$1(browsers),
  1067. oses: constant$1(oses)
  1068. };
  1069. const edge = 'Edge';
  1070. const chromium = 'Chromium';
  1071. const ie = 'IE';
  1072. const opera = 'Opera';
  1073. const firefox = 'Firefox';
  1074. const safari = 'Safari';
  1075. const unknown$2 = () => {
  1076. return nu$c({
  1077. current: undefined,
  1078. version: Version.unknown()
  1079. });
  1080. };
  1081. const nu$c = info => {
  1082. const current = info.current;
  1083. const version = info.version;
  1084. const isBrowser = name => () => current === name;
  1085. return {
  1086. current,
  1087. version,
  1088. isEdge: isBrowser(edge),
  1089. isChromium: isBrowser(chromium),
  1090. isIE: isBrowser(ie),
  1091. isOpera: isBrowser(opera),
  1092. isFirefox: isBrowser(firefox),
  1093. isSafari: isBrowser(safari)
  1094. };
  1095. };
  1096. const Browser = {
  1097. unknown: unknown$2,
  1098. nu: nu$c,
  1099. edge: constant$1(edge),
  1100. chromium: constant$1(chromium),
  1101. ie: constant$1(ie),
  1102. opera: constant$1(opera),
  1103. firefox: constant$1(firefox),
  1104. safari: constant$1(safari)
  1105. };
  1106. const windows = 'Windows';
  1107. const ios = 'iOS';
  1108. const android = 'Android';
  1109. const linux = 'Linux';
  1110. const macos = 'macOS';
  1111. const solaris = 'Solaris';
  1112. const freebsd = 'FreeBSD';
  1113. const chromeos = 'ChromeOS';
  1114. const unknown$1 = () => {
  1115. return nu$b({
  1116. current: undefined,
  1117. version: Version.unknown()
  1118. });
  1119. };
  1120. const nu$b = info => {
  1121. const current = info.current;
  1122. const version = info.version;
  1123. const isOS = name => () => current === name;
  1124. return {
  1125. current,
  1126. version,
  1127. isWindows: isOS(windows),
  1128. isiOS: isOS(ios),
  1129. isAndroid: isOS(android),
  1130. isMacOS: isOS(macos),
  1131. isLinux: isOS(linux),
  1132. isSolaris: isOS(solaris),
  1133. isFreeBSD: isOS(freebsd),
  1134. isChromeOS: isOS(chromeos)
  1135. };
  1136. };
  1137. const OperatingSystem = {
  1138. unknown: unknown$1,
  1139. nu: nu$b,
  1140. windows: constant$1(windows),
  1141. ios: constant$1(ios),
  1142. android: constant$1(android),
  1143. linux: constant$1(linux),
  1144. macos: constant$1(macos),
  1145. solaris: constant$1(solaris),
  1146. freebsd: constant$1(freebsd),
  1147. chromeos: constant$1(chromeos)
  1148. };
  1149. const detect$2 = (userAgent, userAgentDataOpt, mediaMatch) => {
  1150. const browsers = PlatformInfo.browsers();
  1151. const oses = PlatformInfo.oses();
  1152. const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
  1153. const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  1154. const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  1155. return {
  1156. browser,
  1157. os,
  1158. deviceType
  1159. };
  1160. };
  1161. const PlatformDetection = { detect: detect$2 };
  1162. const mediaMatch = query => window.matchMedia(query).matches;
  1163. let platform = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  1164. const detect$1 = () => platform();
  1165. const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
  1166. target,
  1167. x,
  1168. y,
  1169. stop,
  1170. prevent,
  1171. kill,
  1172. raw
  1173. });
  1174. const fromRawEvent$1 = rawEvent => {
  1175. const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
  1176. const stop = () => rawEvent.stopPropagation();
  1177. const prevent = () => rawEvent.preventDefault();
  1178. const kill = compose(prevent, stop);
  1179. return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  1180. };
  1181. const handle = (filter, handler) => rawEvent => {
  1182. if (filter(rawEvent)) {
  1183. handler(fromRawEvent$1(rawEvent));
  1184. }
  1185. };
  1186. const binder = (element, event, filter, handler, useCapture) => {
  1187. const wrapped = handle(filter, handler);
  1188. element.dom.addEventListener(event, wrapped, useCapture);
  1189. return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  1190. };
  1191. const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
  1192. const capture$1 = (element, event, filter, handler) => binder(element, event, filter, handler, true);
  1193. const unbind = (element, event, handler, useCapture) => {
  1194. element.dom.removeEventListener(event, handler, useCapture);
  1195. };
  1196. const before$1 = (marker, element) => {
  1197. const parent$1 = parent(marker);
  1198. parent$1.each(v => {
  1199. v.dom.insertBefore(element.dom, marker.dom);
  1200. });
  1201. };
  1202. const after$2 = (marker, element) => {
  1203. const sibling = nextSibling(marker);
  1204. sibling.fold(() => {
  1205. const parent$1 = parent(marker);
  1206. parent$1.each(v => {
  1207. append$2(v, element);
  1208. });
  1209. }, v => {
  1210. before$1(v, element);
  1211. });
  1212. };
  1213. const prepend$1 = (parent, element) => {
  1214. const firstChild$1 = firstChild(parent);
  1215. firstChild$1.fold(() => {
  1216. append$2(parent, element);
  1217. }, v => {
  1218. parent.dom.insertBefore(element.dom, v.dom);
  1219. });
  1220. };
  1221. const append$2 = (parent, element) => {
  1222. parent.dom.appendChild(element.dom);
  1223. };
  1224. const appendAt = (parent, element, index) => {
  1225. child$2(parent, index).fold(() => {
  1226. append$2(parent, element);
  1227. }, v => {
  1228. before$1(v, element);
  1229. });
  1230. };
  1231. const append$1 = (parent, elements) => {
  1232. each$1(elements, x => {
  1233. append$2(parent, x);
  1234. });
  1235. };
  1236. const empty = element => {
  1237. element.dom.textContent = '';
  1238. each$1(children(element), rogue => {
  1239. remove$5(rogue);
  1240. });
  1241. };
  1242. const remove$5 = element => {
  1243. const dom = element.dom;
  1244. if (dom.parentNode !== null) {
  1245. dom.parentNode.removeChild(dom);
  1246. }
  1247. };
  1248. const get$b = _DOC => {
  1249. const doc = _DOC !== undefined ? _DOC.dom : document;
  1250. const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
  1251. const y = doc.body.scrollTop || doc.documentElement.scrollTop;
  1252. return SugarPosition(x, y);
  1253. };
  1254. const to = (x, y, _DOC) => {
  1255. const doc = _DOC !== undefined ? _DOC.dom : document;
  1256. const win = doc.defaultView;
  1257. if (win) {
  1258. win.scrollTo(x, y);
  1259. }
  1260. };
  1261. const get$a = _win => {
  1262. const win = _win === undefined ? window : _win;
  1263. if (detect$1().browser.isFirefox()) {
  1264. return Optional.none();
  1265. } else {
  1266. return Optional.from(win.visualViewport);
  1267. }
  1268. };
  1269. const bounds$1 = (x, y, width, height) => ({
  1270. x,
  1271. y,
  1272. width,
  1273. height,
  1274. right: x + width,
  1275. bottom: y + height
  1276. });
  1277. const getBounds$3 = _win => {
  1278. const win = _win === undefined ? window : _win;
  1279. const doc = win.document;
  1280. const scroll = get$b(SugarElement.fromDom(doc));
  1281. return get$a(win).fold(() => {
  1282. const html = win.document.documentElement;
  1283. const width = html.clientWidth;
  1284. const height = html.clientHeight;
  1285. return bounds$1(scroll.left, scroll.top, width, height);
  1286. }, visualViewport => bounds$1(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  1287. };
  1288. const getDocument = () => SugarElement.fromDom(document);
  1289. const walkUp = (navigation, doc) => {
  1290. const frame = navigation.view(doc);
  1291. return frame.fold(constant$1([]), f => {
  1292. const parent = navigation.owner(f);
  1293. const rest = walkUp(navigation, parent);
  1294. return [f].concat(rest);
  1295. });
  1296. };
  1297. const pathTo = (element, navigation) => {
  1298. const d = navigation.owner(element);
  1299. const paths = walkUp(navigation, d);
  1300. return Optional.some(paths);
  1301. };
  1302. const view = doc => {
  1303. var _a;
  1304. const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
  1305. return element.map(SugarElement.fromDom);
  1306. };
  1307. const owner$3 = element => owner$4(element);
  1308. var Navigation = /*#__PURE__*/Object.freeze({
  1309. __proto__: null,
  1310. view: view,
  1311. owner: owner$3
  1312. });
  1313. const find$2 = element => {
  1314. const doc = getDocument();
  1315. const scroll = get$b(doc);
  1316. const path = pathTo(element, Navigation);
  1317. return path.fold(curry(absolute$3, element), frames => {
  1318. const offset = viewport$1(element);
  1319. const r = foldr(frames, (b, a) => {
  1320. const loc = viewport$1(a);
  1321. return {
  1322. left: b.left + loc.left,
  1323. top: b.top + loc.top
  1324. };
  1325. }, {
  1326. left: 0,
  1327. top: 0
  1328. });
  1329. return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
  1330. });
  1331. };
  1332. const pointed = (point, width, height) => ({
  1333. point,
  1334. width,
  1335. height
  1336. });
  1337. const rect = (x, y, width, height) => ({
  1338. x,
  1339. y,
  1340. width,
  1341. height
  1342. });
  1343. const bounds = (x, y, width, height) => ({
  1344. x,
  1345. y,
  1346. width,
  1347. height,
  1348. right: x + width,
  1349. bottom: y + height
  1350. });
  1351. const box$1 = element => {
  1352. const xy = absolute$3(element);
  1353. const w = getOuter$1(element);
  1354. const h = getOuter$2(element);
  1355. return bounds(xy.left, xy.top, w, h);
  1356. };
  1357. const absolute$2 = element => {
  1358. const position = find$2(element);
  1359. const width = getOuter$1(element);
  1360. const height = getOuter$2(element);
  1361. return bounds(position.left, position.top, width, height);
  1362. };
  1363. const win = () => getBounds$3(window);
  1364. const value$4 = value => {
  1365. const applyHelper = fn => fn(value);
  1366. const constHelper = constant$1(value);
  1367. const outputHelper = () => output;
  1368. const output = {
  1369. tag: true,
  1370. inner: value,
  1371. fold: (_onError, onValue) => onValue(value),
  1372. isValue: always,
  1373. isError: never,
  1374. map: mapper => Result.value(mapper(value)),
  1375. mapError: outputHelper,
  1376. bind: applyHelper,
  1377. exists: applyHelper,
  1378. forall: applyHelper,
  1379. getOr: constHelper,
  1380. or: outputHelper,
  1381. getOrThunk: constHelper,
  1382. orThunk: outputHelper,
  1383. getOrDie: constHelper,
  1384. each: fn => {
  1385. fn(value);
  1386. },
  1387. toOptional: () => Optional.some(value)
  1388. };
  1389. return output;
  1390. };
  1391. const error$1 = error => {
  1392. const outputHelper = () => output;
  1393. const output = {
  1394. tag: false,
  1395. inner: error,
  1396. fold: (onError, _onValue) => onError(error),
  1397. isValue: never,
  1398. isError: always,
  1399. map: outputHelper,
  1400. mapError: mapper => Result.error(mapper(error)),
  1401. bind: outputHelper,
  1402. exists: never,
  1403. forall: always,
  1404. getOr: identity,
  1405. or: identity,
  1406. getOrThunk: apply,
  1407. orThunk: apply,
  1408. getOrDie: die(String(error)),
  1409. each: noop,
  1410. toOptional: Optional.none
  1411. };
  1412. return output;
  1413. };
  1414. const fromOption = (optional, err) => optional.fold(() => error$1(err), value$4);
  1415. const Result = {
  1416. value: value$4,
  1417. error: error$1,
  1418. fromOption
  1419. };
  1420. var SimpleResultType;
  1421. (function (SimpleResultType) {
  1422. SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
  1423. SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
  1424. }(SimpleResultType || (SimpleResultType = {})));
  1425. const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
  1426. const partition$2 = results => {
  1427. const values = [];
  1428. const errors = [];
  1429. each$1(results, obj => {
  1430. fold$1(obj, err => errors.push(err), val => values.push(val));
  1431. });
  1432. return {
  1433. values,
  1434. errors
  1435. };
  1436. };
  1437. const mapError = (res, f) => {
  1438. if (res.stype === SimpleResultType.Error) {
  1439. return {
  1440. stype: SimpleResultType.Error,
  1441. serror: f(res.serror)
  1442. };
  1443. } else {
  1444. return res;
  1445. }
  1446. };
  1447. const map = (res, f) => {
  1448. if (res.stype === SimpleResultType.Value) {
  1449. return {
  1450. stype: SimpleResultType.Value,
  1451. svalue: f(res.svalue)
  1452. };
  1453. } else {
  1454. return res;
  1455. }
  1456. };
  1457. const bind$1 = (res, f) => {
  1458. if (res.stype === SimpleResultType.Value) {
  1459. return f(res.svalue);
  1460. } else {
  1461. return res;
  1462. }
  1463. };
  1464. const bindError = (res, f) => {
  1465. if (res.stype === SimpleResultType.Error) {
  1466. return f(res.serror);
  1467. } else {
  1468. return res;
  1469. }
  1470. };
  1471. const svalue = v => ({
  1472. stype: SimpleResultType.Value,
  1473. svalue: v
  1474. });
  1475. const serror = e => ({
  1476. stype: SimpleResultType.Error,
  1477. serror: e
  1478. });
  1479. const toResult$1 = res => fold$1(res, Result.error, Result.value);
  1480. const fromResult$1 = res => res.fold(serror, svalue);
  1481. const SimpleResult = {
  1482. fromResult: fromResult$1,
  1483. toResult: toResult$1,
  1484. svalue,
  1485. partition: partition$2,
  1486. serror,
  1487. bind: bind$1,
  1488. bindError,
  1489. map,
  1490. mapError,
  1491. fold: fold$1
  1492. };
  1493. const field$2 = (key, newKey, presence, prop) => ({
  1494. tag: 'field',
  1495. key,
  1496. newKey,
  1497. presence,
  1498. prop
  1499. });
  1500. const customField$1 = (newKey, instantiator) => ({
  1501. tag: 'custom',
  1502. newKey,
  1503. instantiator
  1504. });
  1505. const fold = (value, ifField, ifCustom) => {
  1506. switch (value.tag) {
  1507. case 'field':
  1508. return ifField(value.key, value.newKey, value.presence, value.prop);
  1509. case 'custom':
  1510. return ifCustom(value.newKey, value.instantiator);
  1511. }
  1512. };
  1513. const shallow$1 = (old, nu) => {
  1514. return nu;
  1515. };
  1516. const deep = (old, nu) => {
  1517. const bothObjects = isPlainObject(old) && isPlainObject(nu);
  1518. return bothObjects ? deepMerge(old, nu) : nu;
  1519. };
  1520. const baseMerge = merger => {
  1521. return (...objects) => {
  1522. if (objects.length === 0) {
  1523. throw new Error(`Can't merge zero objects`);
  1524. }
  1525. const ret = {};
  1526. for (let j = 0; j < objects.length; j++) {
  1527. const curObject = objects[j];
  1528. for (const key in curObject) {
  1529. if (has$2(curObject, key)) {
  1530. ret[key] = merger(ret[key], curObject[key]);
  1531. }
  1532. }
  1533. }
  1534. return ret;
  1535. };
  1536. };
  1537. const deepMerge = baseMerge(deep);
  1538. const merge$1 = baseMerge(shallow$1);
  1539. const required$2 = () => ({
  1540. tag: 'required',
  1541. process: {}
  1542. });
  1543. const defaultedThunk = fallbackThunk => ({
  1544. tag: 'defaultedThunk',
  1545. process: fallbackThunk
  1546. });
  1547. const defaulted$1 = fallback => defaultedThunk(constant$1(fallback));
  1548. const asOption = () => ({
  1549. tag: 'option',
  1550. process: {}
  1551. });
  1552. const mergeWithThunk = baseThunk => ({
  1553. tag: 'mergeWithThunk',
  1554. process: baseThunk
  1555. });
  1556. const mergeWith = base => mergeWithThunk(constant$1(base));
  1557. const mergeValues$1 = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge$1.apply(undefined, values))) : SimpleResult.svalue(base);
  1558. const mergeErrors$1 = errors => compose(SimpleResult.serror, flatten)(errors);
  1559. const consolidateObj = (objects, base) => {
  1560. const partition = SimpleResult.partition(objects);
  1561. return partition.errors.length > 0 ? mergeErrors$1(partition.errors) : mergeValues$1(partition.values, base);
  1562. };
  1563. const consolidateArr = objects => {
  1564. const partitions = SimpleResult.partition(objects);
  1565. return partitions.errors.length > 0 ? mergeErrors$1(partitions.errors) : SimpleResult.svalue(partitions.values);
  1566. };
  1567. const ResultCombine = {
  1568. consolidateObj,
  1569. consolidateArr
  1570. };
  1571. const formatObj = input => {
  1572. return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
  1573. };
  1574. const formatErrors = errors => {
  1575. const es = errors.length > 10 ? errors.slice(0, 10).concat([{
  1576. path: [],
  1577. getErrorInfo: constant$1('... (only showing first ten failures)')
  1578. }]) : errors;
  1579. return map$2(es, e => {
  1580. return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
  1581. });
  1582. };
  1583. const nu$a = (path, getErrorInfo) => {
  1584. return SimpleResult.serror([{
  1585. path,
  1586. getErrorInfo
  1587. }]);
  1588. };
  1589. const missingRequired = (path, key, obj) => nu$a(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
  1590. const missingKey = (path, key) => nu$a(path, () => 'Choice schema did not contain choice key: "' + key + '"');
  1591. const missingBranch = (path, branches, branch) => nu$a(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
  1592. const unsupportedFields = (path, unsupported) => nu$a(path, () => 'There are unsupported fields: [' + unsupported.join(', ') + '] specified');
  1593. const custom = (path, err) => nu$a(path, constant$1(err));
  1594. const value$3 = validator => {
  1595. const extract = (path, val) => {
  1596. return SimpleResult.bindError(validator(val), err => custom(path, err));
  1597. };
  1598. const toString = constant$1('val');
  1599. return {
  1600. extract,
  1601. toString
  1602. };
  1603. };
  1604. const anyValue$1 = value$3(SimpleResult.svalue);
  1605. const requiredAccess = (path, obj, key, bundle) => get$g(obj, key).fold(() => missingRequired(path, key, obj), bundle);
  1606. const fallbackAccess = (obj, key, fallback, bundle) => {
  1607. const v = get$g(obj, key).getOrThunk(() => fallback(obj));
  1608. return bundle(v);
  1609. };
  1610. const optionAccess = (obj, key, bundle) => bundle(get$g(obj, key));
  1611. const optionDefaultedAccess = (obj, key, fallback, bundle) => {
  1612. const opt = get$g(obj, key).map(val => val === true ? fallback(obj) : val);
  1613. return bundle(opt);
  1614. };
  1615. const extractField = (field, path, obj, key, prop) => {
  1616. const bundle = av => prop.extract(path.concat([key]), av);
  1617. const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
  1618. const result = prop.extract(path.concat([key]), ov);
  1619. return SimpleResult.map(result, Optional.some);
  1620. });
  1621. switch (field.tag) {
  1622. case 'required':
  1623. return requiredAccess(path, obj, key, bundle);
  1624. case 'defaultedThunk':
  1625. return fallbackAccess(obj, key, field.process, bundle);
  1626. case 'option':
  1627. return optionAccess(obj, key, bundleAsOption);
  1628. case 'defaultedOptionThunk':
  1629. return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
  1630. case 'mergeWithThunk': {
  1631. return fallbackAccess(obj, key, constant$1({}), v => {
  1632. const result = deepMerge(field.process(obj), v);
  1633. return bundle(result);
  1634. });
  1635. }
  1636. }
  1637. };
  1638. const extractFields = (path, obj, fields) => {
  1639. const success = {};
  1640. const errors = [];
  1641. for (const field of fields) {
  1642. fold(field, (key, newKey, presence, prop) => {
  1643. const result = extractField(presence, path, obj, key, prop);
  1644. SimpleResult.fold(result, err => {
  1645. errors.push(...err);
  1646. }, res => {
  1647. success[newKey] = res;
  1648. });
  1649. }, (newKey, instantiator) => {
  1650. success[newKey] = instantiator(obj);
  1651. });
  1652. }
  1653. return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
  1654. };
  1655. const valueThunk = getDelegate => {
  1656. const extract = (path, val) => getDelegate().extract(path, val);
  1657. const toString = () => getDelegate().toString();
  1658. return {
  1659. extract,
  1660. toString
  1661. };
  1662. };
  1663. const getSetKeys = obj => keys(filter$1(obj, isNonNullable));
  1664. const objOfOnly = fields => {
  1665. const delegate = objOf(fields);
  1666. const fieldNames = foldr(fields, (acc, value) => {
  1667. return fold(value, key => deepMerge(acc, { [key]: true }), constant$1(acc));
  1668. }, {});
  1669. const extract = (path, o) => {
  1670. const keys = isBoolean(o) ? [] : getSetKeys(o);
  1671. const extra = filter$2(keys, k => !hasNonNullableKey(fieldNames, k));
  1672. return extra.length === 0 ? delegate.extract(path, o) : unsupportedFields(path, extra);
  1673. };
  1674. return {
  1675. extract,
  1676. toString: delegate.toString
  1677. };
  1678. };
  1679. const objOf = values => {
  1680. const extract = (path, o) => extractFields(path, o, values);
  1681. const toString = () => {
  1682. const fieldStrings = map$2(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
  1683. return 'obj{\n' + fieldStrings.join('\n') + '}';
  1684. };
  1685. return {
  1686. extract,
  1687. toString
  1688. };
  1689. };
  1690. const arrOf = prop => {
  1691. const extract = (path, array) => {
  1692. const results = map$2(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
  1693. return ResultCombine.consolidateArr(results);
  1694. };
  1695. const toString = () => 'array(' + prop.toString() + ')';
  1696. return {
  1697. extract,
  1698. toString
  1699. };
  1700. };
  1701. const oneOf = props => {
  1702. const extract = (path, val) => {
  1703. const errors = [];
  1704. for (const prop of props) {
  1705. const res = prop.extract(path, val);
  1706. if (res.stype === SimpleResultType.Value) {
  1707. return res;
  1708. }
  1709. errors.push(res);
  1710. }
  1711. return ResultCombine.consolidateArr(errors);
  1712. };
  1713. const toString = () => 'oneOf(' + map$2(props, prop => prop.toString()).join(', ') + ')';
  1714. return {
  1715. extract,
  1716. toString
  1717. };
  1718. };
  1719. const setOf$1 = (validator, prop) => {
  1720. const validateKeys = (path, keys) => arrOf(value$3(validator)).extract(path, keys);
  1721. const extract = (path, o) => {
  1722. const keys$1 = keys(o);
  1723. const validatedKeys = validateKeys(path, keys$1);
  1724. return SimpleResult.bind(validatedKeys, validKeys => {
  1725. const schema = map$2(validKeys, vk => {
  1726. return field$2(vk, vk, required$2(), prop);
  1727. });
  1728. return objOf(schema).extract(path, o);
  1729. });
  1730. };
  1731. const toString = () => 'setOf(' + prop.toString() + ')';
  1732. return {
  1733. extract,
  1734. toString
  1735. };
  1736. };
  1737. const thunk = (_desc, processor) => {
  1738. const getP = cached(processor);
  1739. const extract = (path, val) => getP().extract(path, val);
  1740. const toString = () => getP().toString();
  1741. return {
  1742. extract,
  1743. toString
  1744. };
  1745. };
  1746. const arrOfObj = compose(arrOf, objOf);
  1747. const anyValue = constant$1(anyValue$1);
  1748. const typedValue = (validator, expectedType) => value$3(a => {
  1749. const actualType = typeof a;
  1750. return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
  1751. });
  1752. const number = typedValue(isNumber, 'number');
  1753. const string = typedValue(isString, 'string');
  1754. const boolean = typedValue(isBoolean, 'boolean');
  1755. const functionProcessor = typedValue(isFunction, 'function');
  1756. const isPostMessageable = val => {
  1757. if (Object(val) !== val) {
  1758. return true;
  1759. }
  1760. switch ({}.toString.call(val).slice(8, -1)) {
  1761. case 'Boolean':
  1762. case 'Number':
  1763. case 'String':
  1764. case 'Date':
  1765. case 'RegExp':
  1766. case 'Blob':
  1767. case 'FileList':
  1768. case 'ImageData':
  1769. case 'ImageBitmap':
  1770. case 'ArrayBuffer':
  1771. return true;
  1772. case 'Array':
  1773. case 'Object':
  1774. return Object.keys(val).every(prop => isPostMessageable(val[prop]));
  1775. default:
  1776. return false;
  1777. }
  1778. };
  1779. const postMessageable = value$3(a => {
  1780. if (isPostMessageable(a)) {
  1781. return SimpleResult.svalue(a);
  1782. } else {
  1783. return SimpleResult.serror('Expected value to be acceptable for sending via postMessage');
  1784. }
  1785. });
  1786. const chooseFrom = (path, input, branches, ch) => {
  1787. const fields = get$g(branches, ch);
  1788. return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
  1789. };
  1790. const choose$2 = (key, branches) => {
  1791. const extract = (path, input) => {
  1792. const choice = get$g(input, key);
  1793. return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
  1794. };
  1795. const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
  1796. return {
  1797. extract,
  1798. toString
  1799. };
  1800. };
  1801. const arrOfVal = () => arrOf(anyValue$1);
  1802. const valueOf = validator => value$3(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
  1803. const setOf = (validator, prop) => setOf$1(v => SimpleResult.fromResult(validator(v)), prop);
  1804. const extractValue = (label, prop, obj) => {
  1805. const res = prop.extract([label], obj);
  1806. return SimpleResult.mapError(res, errs => ({
  1807. input: obj,
  1808. errors: errs
  1809. }));
  1810. };
  1811. const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
  1812. const getOrDie = extraction => {
  1813. return extraction.fold(errInfo => {
  1814. throw new Error(formatError(errInfo));
  1815. }, identity);
  1816. };
  1817. const asRawOrDie$1 = (label, prop, obj) => getOrDie(asRaw(label, prop, obj));
  1818. const formatError = errInfo => {
  1819. return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
  1820. };
  1821. const choose$1 = (key, branches) => choose$2(key, map$1(branches, objOf));
  1822. const thunkOf = (desc, schema) => thunk(desc, schema);
  1823. const field$1 = field$2;
  1824. const customField = customField$1;
  1825. const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
  1826. const required$1 = key => field$1(key, key, required$2(), anyValue());
  1827. const requiredOf = (key, schema) => field$1(key, key, required$2(), schema);
  1828. const requiredNumber = key => requiredOf(key, number);
  1829. const requiredString = key => requiredOf(key, string);
  1830. const requiredStringEnum = (key, values) => field$1(key, key, required$2(), validateEnum(values));
  1831. const requiredBoolean = key => requiredOf(key, boolean);
  1832. const requiredFunction = key => requiredOf(key, functionProcessor);
  1833. const forbid = (key, message) => field$1(key, key, asOption(), value$3(_v => SimpleResult.serror('The field: ' + key + ' is forbidden. ' + message)));
  1834. const requiredObjOf = (key, objSchema) => field$1(key, key, required$2(), objOf(objSchema));
  1835. const requiredArrayOfObj = (key, objFields) => field$1(key, key, required$2(), arrOfObj(objFields));
  1836. const requiredArrayOf = (key, schema) => field$1(key, key, required$2(), arrOf(schema));
  1837. const option$3 = key => field$1(key, key, asOption(), anyValue());
  1838. const optionOf = (key, schema) => field$1(key, key, asOption(), schema);
  1839. const optionNumber = key => optionOf(key, number);
  1840. const optionString = key => optionOf(key, string);
  1841. const optionStringEnum = (key, values) => optionOf(key, validateEnum(values));
  1842. const optionFunction = key => optionOf(key, functionProcessor);
  1843. const optionArrayOf = (key, schema) => optionOf(key, arrOf(schema));
  1844. const optionObjOf = (key, objSchema) => optionOf(key, objOf(objSchema));
  1845. const optionObjOfOnly = (key, objSchema) => optionOf(key, objOfOnly(objSchema));
  1846. const defaulted = (key, fallback) => field$1(key, key, defaulted$1(fallback), anyValue());
  1847. const defaultedOf = (key, fallback, schema) => field$1(key, key, defaulted$1(fallback), schema);
  1848. const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
  1849. const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
  1850. const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
  1851. const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
  1852. const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
  1853. const defaultedPostMsg = (key, fallback) => defaultedOf(key, fallback, postMessageable);
  1854. const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
  1855. const defaultedObjOf = (key, fallback, objSchema) => defaultedOf(key, fallback, objOf(objSchema));
  1856. const Cell = initial => {
  1857. let value = initial;
  1858. const get = () => {
  1859. return value;
  1860. };
  1861. const set = v => {
  1862. value = v;
  1863. };
  1864. return {
  1865. get,
  1866. set
  1867. };
  1868. };
  1869. const generate$7 = cases => {
  1870. if (!isArray(cases)) {
  1871. throw new Error('cases must be an array');
  1872. }
  1873. if (cases.length === 0) {
  1874. throw new Error('there must be at least one case');
  1875. }
  1876. const constructors = [];
  1877. const adt = {};
  1878. each$1(cases, (acase, count) => {
  1879. const keys$1 = keys(acase);
  1880. if (keys$1.length !== 1) {
  1881. throw new Error('one and only one name per case');
  1882. }
  1883. const key = keys$1[0];
  1884. const value = acase[key];
  1885. if (adt[key] !== undefined) {
  1886. throw new Error('duplicate key detected:' + key);
  1887. } else if (key === 'cata') {
  1888. throw new Error('cannot have a case named cata (sorry)');
  1889. } else if (!isArray(value)) {
  1890. throw new Error('case arguments must be an array');
  1891. }
  1892. constructors.push(key);
  1893. adt[key] = (...args) => {
  1894. const argLength = args.length;
  1895. if (argLength !== value.length) {
  1896. throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
  1897. }
  1898. const match = branches => {
  1899. const branchKeys = keys(branches);
  1900. if (constructors.length !== branchKeys.length) {
  1901. throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
  1902. }
  1903. const allReqd = forall(constructors, reqKey => {
  1904. return contains$2(branchKeys, reqKey);
  1905. });
  1906. if (!allReqd) {
  1907. throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
  1908. }
  1909. return branches[key].apply(null, args);
  1910. };
  1911. return {
  1912. fold: (...foldArgs) => {
  1913. if (foldArgs.length !== cases.length) {
  1914. throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
  1915. }
  1916. const target = foldArgs[count];
  1917. return target.apply(null, args);
  1918. },
  1919. match,
  1920. log: label => {
  1921. console.log(label, {
  1922. constructors,
  1923. constructor: key,
  1924. params: args
  1925. });
  1926. }
  1927. };
  1928. };
  1929. });
  1930. return adt;
  1931. };
  1932. const Adt = { generate: generate$7 };
  1933. Adt.generate([
  1934. {
  1935. bothErrors: [
  1936. 'error1',
  1937. 'error2'
  1938. ]
  1939. },
  1940. {
  1941. firstError: [
  1942. 'error1',
  1943. 'value2'
  1944. ]
  1945. },
  1946. {
  1947. secondError: [
  1948. 'value1',
  1949. 'error2'
  1950. ]
  1951. },
  1952. {
  1953. bothValues: [
  1954. 'value1',
  1955. 'value2'
  1956. ]
  1957. }
  1958. ]);
  1959. const partition$1 = results => {
  1960. const errors = [];
  1961. const values = [];
  1962. each$1(results, result => {
  1963. result.fold(err => {
  1964. errors.push(err);
  1965. }, value => {
  1966. values.push(value);
  1967. });
  1968. });
  1969. return {
  1970. errors,
  1971. values
  1972. };
  1973. };
  1974. const exclude$1 = (obj, fields) => {
  1975. const r = {};
  1976. each(obj, (v, k) => {
  1977. if (!contains$2(fields, k)) {
  1978. r[k] = v;
  1979. }
  1980. });
  1981. return r;
  1982. };
  1983. const wrap$2 = (key, value) => ({ [key]: value });
  1984. const wrapAll$1 = keyvalues => {
  1985. const r = {};
  1986. each$1(keyvalues, kv => {
  1987. r[kv.key] = kv.value;
  1988. });
  1989. return r;
  1990. };
  1991. const exclude = (obj, fields) => exclude$1(obj, fields);
  1992. const wrap$1 = (key, value) => wrap$2(key, value);
  1993. const wrapAll = keyvalues => wrapAll$1(keyvalues);
  1994. const mergeValues = (values, base) => {
  1995. return values.length === 0 ? Result.value(base) : Result.value(deepMerge(base, merge$1.apply(undefined, values)));
  1996. };
  1997. const mergeErrors = errors => Result.error(flatten(errors));
  1998. const consolidate = (objs, base) => {
  1999. const partitions = partition$1(objs);
  2000. return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : mergeValues(partitions.values, base);
  2001. };
  2002. const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
  2003. const ancestor$2 = (scope, transform, isRoot) => {
  2004. let element = scope.dom;
  2005. const stop = ensureIsRoot(isRoot);
  2006. while (element.parentNode) {
  2007. element = element.parentNode;
  2008. const el = SugarElement.fromDom(element);
  2009. const transformed = transform(el);
  2010. if (transformed.isSome()) {
  2011. return transformed;
  2012. } else if (stop(el)) {
  2013. break;
  2014. }
  2015. }
  2016. return Optional.none();
  2017. };
  2018. const closest$4 = (scope, transform, isRoot) => {
  2019. const current = transform(scope);
  2020. const stop = ensureIsRoot(isRoot);
  2021. return current.orThunk(() => stop(scope) ? Optional.none() : ancestor$2(scope, transform, stop));
  2022. };
  2023. const isSource = (component, simulatedEvent) => eq(component.element, simulatedEvent.event.target);
  2024. const defaultEventHandler = {
  2025. can: always,
  2026. abort: never,
  2027. run: noop
  2028. };
  2029. const nu$9 = parts => {
  2030. if (!hasNonNullableKey(parts, 'can') && !hasNonNullableKey(parts, 'abort') && !hasNonNullableKey(parts, 'run')) {
  2031. throw new Error('EventHandler defined by: ' + JSON.stringify(parts, null, 2) + ' does not have can, abort, or run!');
  2032. }
  2033. return {
  2034. ...defaultEventHandler,
  2035. ...parts
  2036. };
  2037. };
  2038. const all$2 = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc && f(handler).apply(undefined, args), true);
  2039. const any = (handlers, f) => (...args) => foldl(handlers, (acc, handler) => acc || f(handler).apply(undefined, args), false);
  2040. const read$2 = handler => isFunction(handler) ? {
  2041. can: always,
  2042. abort: never,
  2043. run: handler
  2044. } : handler;
  2045. const fuse$1 = handlers => {
  2046. const can = all$2(handlers, handler => handler.can);
  2047. const abort = any(handlers, handler => handler.abort);
  2048. const run = (...args) => {
  2049. each$1(handlers, handler => {
  2050. handler.run.apply(undefined, args);
  2051. });
  2052. };
  2053. return {
  2054. can,
  2055. abort,
  2056. run
  2057. };
  2058. };
  2059. const constant = constant$1;
  2060. const touchstart = constant('touchstart');
  2061. const touchmove = constant('touchmove');
  2062. const touchend = constant('touchend');
  2063. const touchcancel = constant('touchcancel');
  2064. const mousedown = constant('mousedown');
  2065. const mousemove = constant('mousemove');
  2066. const mouseout = constant('mouseout');
  2067. const mouseup = constant('mouseup');
  2068. const mouseover = constant('mouseover');
  2069. const focusin = constant('focusin');
  2070. const focusout = constant('focusout');
  2071. const keydown = constant('keydown');
  2072. const keyup = constant('keyup');
  2073. const input = constant('input');
  2074. const change = constant('change');
  2075. const click = constant('click');
  2076. const transitioncancel = constant('transitioncancel');
  2077. const transitionend = constant('transitionend');
  2078. const transitionstart = constant('transitionstart');
  2079. const selectstart = constant('selectstart');
  2080. const prefixName = name => constant$1('alloy.' + name);
  2081. const alloy = { tap: prefixName('tap') };
  2082. const focus$4 = prefixName('focus');
  2083. const postBlur = prefixName('blur.post');
  2084. const postPaste = prefixName('paste.post');
  2085. const receive = prefixName('receive');
  2086. const execute$5 = prefixName('execute');
  2087. const focusItem = prefixName('focus.item');
  2088. const tap = alloy.tap;
  2089. const longpress = prefixName('longpress');
  2090. const sandboxClose = prefixName('sandbox.close');
  2091. const typeaheadCancel = prefixName('typeahead.cancel');
  2092. const systemInit = prefixName('system.init');
  2093. const documentTouchmove = prefixName('system.touchmove');
  2094. const documentTouchend = prefixName('system.touchend');
  2095. const windowScroll = prefixName('system.scroll');
  2096. const windowResize = prefixName('system.resize');
  2097. const attachedToDom = prefixName('system.attached');
  2098. const detachedFromDom = prefixName('system.detached');
  2099. const dismissRequested = prefixName('system.dismissRequested');
  2100. const repositionRequested = prefixName('system.repositionRequested');
  2101. const focusShifted = prefixName('focusmanager.shifted');
  2102. const slotVisibility = prefixName('slotcontainer.visibility');
  2103. const changeTab = prefixName('change.tab');
  2104. const dismissTab = prefixName('dismiss.tab');
  2105. const highlight$1 = prefixName('highlight');
  2106. const dehighlight$1 = prefixName('dehighlight');
  2107. const emit = (component, event) => {
  2108. dispatchWith(component, component.element, event, {});
  2109. };
  2110. const emitWith = (component, event, properties) => {
  2111. dispatchWith(component, component.element, event, properties);
  2112. };
  2113. const emitExecute = component => {
  2114. emit(component, execute$5());
  2115. };
  2116. const dispatch = (component, target, event) => {
  2117. dispatchWith(component, target, event, {});
  2118. };
  2119. const dispatchWith = (component, target, event, properties) => {
  2120. const data = {
  2121. target,
  2122. ...properties
  2123. };
  2124. component.getSystem().triggerEvent(event, target, data);
  2125. };
  2126. const dispatchEvent = (component, target, event, simulatedEvent) => {
  2127. component.getSystem().triggerEvent(event, target, simulatedEvent.event);
  2128. };
  2129. const derive$2 = configs => wrapAll(configs);
  2130. const abort = (name, predicate) => {
  2131. return {
  2132. key: name,
  2133. value: nu$9({ abort: predicate })
  2134. };
  2135. };
  2136. const can = (name, predicate) => {
  2137. return {
  2138. key: name,
  2139. value: nu$9({ can: predicate })
  2140. };
  2141. };
  2142. const preventDefault = name => {
  2143. return {
  2144. key: name,
  2145. value: nu$9({
  2146. run: (component, simulatedEvent) => {
  2147. simulatedEvent.event.prevent();
  2148. }
  2149. })
  2150. };
  2151. };
  2152. const run$1 = (name, handler) => {
  2153. return {
  2154. key: name,
  2155. value: nu$9({ run: handler })
  2156. };
  2157. };
  2158. const runActionExtra = (name, action, extra) => {
  2159. return {
  2160. key: name,
  2161. value: nu$9({
  2162. run: (component, simulatedEvent) => {
  2163. action.apply(undefined, [
  2164. component,
  2165. simulatedEvent
  2166. ].concat(extra));
  2167. }
  2168. })
  2169. };
  2170. };
  2171. const runOnName = name => {
  2172. return handler => run$1(name, handler);
  2173. };
  2174. const runOnSourceName = name => {
  2175. return handler => ({
  2176. key: name,
  2177. value: nu$9({
  2178. run: (component, simulatedEvent) => {
  2179. if (isSource(component, simulatedEvent)) {
  2180. handler(component, simulatedEvent);
  2181. }
  2182. }
  2183. })
  2184. });
  2185. };
  2186. const redirectToUid = (name, uid) => {
  2187. return run$1(name, (component, simulatedEvent) => {
  2188. component.getSystem().getByUid(uid).each(redirectee => {
  2189. dispatchEvent(redirectee, redirectee.element, name, simulatedEvent);
  2190. });
  2191. });
  2192. };
  2193. const redirectToPart = (name, detail, partName) => {
  2194. const uid = detail.partUids[partName];
  2195. return redirectToUid(name, uid);
  2196. };
  2197. const runWithTarget = (name, f) => {
  2198. return run$1(name, (component, simulatedEvent) => {
  2199. const ev = simulatedEvent.event;
  2200. const target = component.getSystem().getByDom(ev.target).getOrThunk(() => {
  2201. const closest = closest$4(ev.target, el => component.getSystem().getByDom(el).toOptional(), never);
  2202. return closest.getOr(component);
  2203. });
  2204. f(component, target, simulatedEvent);
  2205. });
  2206. };
  2207. const cutter = name => {
  2208. return run$1(name, (component, simulatedEvent) => {
  2209. simulatedEvent.cut();
  2210. });
  2211. };
  2212. const stopper = name => {
  2213. return run$1(name, (component, simulatedEvent) => {
  2214. simulatedEvent.stop();
  2215. });
  2216. };
  2217. const runOnSource = (name, f) => {
  2218. return runOnSourceName(name)(f);
  2219. };
  2220. const runOnAttached = runOnSourceName(attachedToDom());
  2221. const runOnDetached = runOnSourceName(detachedFromDom());
  2222. const runOnInit = runOnSourceName(systemInit());
  2223. const runOnExecute$1 = runOnName(execute$5());
  2224. const fromHtml$1 = (html, scope) => {
  2225. const doc = scope || document;
  2226. const div = doc.createElement('div');
  2227. div.innerHTML = html;
  2228. return children(SugarElement.fromDom(div));
  2229. };
  2230. const get$9 = element => element.dom.innerHTML;
  2231. const set$6 = (element, content) => {
  2232. const owner = owner$4(element);
  2233. const docDom = owner.dom;
  2234. const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
  2235. const contentElements = fromHtml$1(content, docDom);
  2236. append$1(fragment, contentElements);
  2237. empty(element);
  2238. append$2(element, fragment);
  2239. };
  2240. const getOuter = element => {
  2241. const container = SugarElement.fromTag('div');
  2242. const clone = SugarElement.fromDom(element.dom.cloneNode(true));
  2243. append$2(container, clone);
  2244. return get$9(container);
  2245. };
  2246. const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  2247. const shallow = original => clone(original, false);
  2248. const getHtml = element => {
  2249. if (isShadowRoot(element)) {
  2250. return '#shadow-root';
  2251. } else {
  2252. const clone = shallow(element);
  2253. return getOuter(clone);
  2254. }
  2255. };
  2256. const element = elem => getHtml(elem);
  2257. const isRecursive = (component, originator, target) => eq(originator, component.element) && !eq(originator, target);
  2258. const events$i = derive$2([can(focus$4(), (component, simulatedEvent) => {
  2259. const event = simulatedEvent.event;
  2260. const originator = event.originator;
  2261. const target = event.target;
  2262. if (isRecursive(component, originator, target)) {
  2263. console.warn(focus$4() + ' did not get interpreted by the desired target. ' + '\nOriginator: ' + element(originator) + '\nTarget: ' + element(target) + '\nCheck the ' + focus$4() + ' event handlers');
  2264. return false;
  2265. } else {
  2266. return true;
  2267. }
  2268. })]);
  2269. var DefaultEvents = /*#__PURE__*/Object.freeze({
  2270. __proto__: null,
  2271. events: events$i
  2272. });
  2273. let unique = 0;
  2274. const generate$6 = prefix => {
  2275. const date = new Date();
  2276. const time = date.getTime();
  2277. const random = Math.floor(Math.random() * 1000000000);
  2278. unique++;
  2279. return prefix + '_' + random + unique + String(time);
  2280. };
  2281. const prefix$1 = constant$1('alloy-id-');
  2282. const idAttr$1 = constant$1('data-alloy-id');
  2283. const prefix = prefix$1();
  2284. const idAttr = idAttr$1();
  2285. const write = (label, elem) => {
  2286. const id = generate$6(prefix + label);
  2287. writeOnly(elem, id);
  2288. return id;
  2289. };
  2290. const writeOnly = (elem, uid) => {
  2291. Object.defineProperty(elem.dom, idAttr, {
  2292. value: uid,
  2293. writable: true
  2294. });
  2295. };
  2296. const read$1 = elem => {
  2297. const id = isElement$1(elem) ? elem.dom[idAttr] : null;
  2298. return Optional.from(id);
  2299. };
  2300. const generate$5 = prefix => generate$6(prefix);
  2301. const make$8 = identity;
  2302. const NoContextApi = getComp => {
  2303. const getMessage = event => `The component must be in a context to execute: ${ event }` + (getComp ? '\n' + element(getComp().element) + ' is not in context.' : '');
  2304. const fail = event => () => {
  2305. throw new Error(getMessage(event));
  2306. };
  2307. const warn = event => () => {
  2308. console.warn(getMessage(event));
  2309. };
  2310. return {
  2311. debugInfo: constant$1('fake'),
  2312. triggerEvent: warn('triggerEvent'),
  2313. triggerFocus: warn('triggerFocus'),
  2314. triggerEscape: warn('triggerEscape'),
  2315. broadcast: warn('broadcast'),
  2316. broadcastOn: warn('broadcastOn'),
  2317. broadcastEvent: warn('broadcastEvent'),
  2318. build: fail('build'),
  2319. buildOrPatch: fail('buildOrPatch'),
  2320. addToWorld: fail('addToWorld'),
  2321. removeFromWorld: fail('removeFromWorld'),
  2322. addToGui: fail('addToGui'),
  2323. removeFromGui: fail('removeFromGui'),
  2324. getByUid: fail('getByUid'),
  2325. getByDom: fail('getByDom'),
  2326. isConnected: never
  2327. };
  2328. };
  2329. const singleton$1 = NoContextApi();
  2330. const markAsBehaviourApi = (f, apiName, apiFunction) => {
  2331. const delegate = apiFunction.toString();
  2332. const endIndex = delegate.indexOf(')') + 1;
  2333. const openBracketIndex = delegate.indexOf('(');
  2334. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2335. f.toFunctionAnnotation = () => ({
  2336. name: apiName,
  2337. parameters: cleanParameters(parameters.slice(0, 1).concat(parameters.slice(3)))
  2338. });
  2339. return f;
  2340. };
  2341. const cleanParameters = parameters => map$2(parameters, p => endsWith(p, '/*') ? p.substring(0, p.length - '/*'.length) : p);
  2342. const markAsExtraApi = (f, extraName) => {
  2343. const delegate = f.toString();
  2344. const endIndex = delegate.indexOf(')') + 1;
  2345. const openBracketIndex = delegate.indexOf('(');
  2346. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2347. f.toFunctionAnnotation = () => ({
  2348. name: extraName,
  2349. parameters: cleanParameters(parameters)
  2350. });
  2351. return f;
  2352. };
  2353. const markAsSketchApi = (f, apiFunction) => {
  2354. const delegate = apiFunction.toString();
  2355. const endIndex = delegate.indexOf(')') + 1;
  2356. const openBracketIndex = delegate.indexOf('(');
  2357. const parameters = delegate.substring(openBracketIndex + 1, endIndex - 1).split(/,\s*/);
  2358. f.toFunctionAnnotation = () => ({
  2359. name: 'OVERRIDE',
  2360. parameters: cleanParameters(parameters.slice(1))
  2361. });
  2362. return f;
  2363. };
  2364. const premadeTag = generate$6('alloy-premade');
  2365. const premade$1 = comp => {
  2366. Object.defineProperty(comp.element.dom, premadeTag, {
  2367. value: comp.uid,
  2368. writable: true
  2369. });
  2370. return wrap$1(premadeTag, comp);
  2371. };
  2372. const isPremade = element => has$2(element.dom, premadeTag);
  2373. const getPremade = spec => get$g(spec, premadeTag);
  2374. const makeApi = f => markAsSketchApi((component, ...rest) => f(component.getApis(), component, ...rest), f);
  2375. const NoState = { init: () => nu$8({ readState: constant$1('No State required') }) };
  2376. const nu$8 = spec => spec;
  2377. const generateFrom$1 = (spec, all) => {
  2378. const schema = map$2(all, a => optionObjOf(a.name(), [
  2379. required$1('config'),
  2380. defaulted('state', NoState)
  2381. ]));
  2382. const validated = asRaw('component.behaviours', objOf(schema), spec.behaviours).fold(errInfo => {
  2383. throw new Error(formatError(errInfo) + '\nComplete spec:\n' + JSON.stringify(spec, null, 2));
  2384. }, identity);
  2385. return {
  2386. list: all,
  2387. data: map$1(validated, optBlobThunk => {
  2388. const output = optBlobThunk.map(blob => ({
  2389. config: blob.config,
  2390. state: blob.state.init(blob.config)
  2391. }));
  2392. return constant$1(output);
  2393. })
  2394. };
  2395. };
  2396. const getBehaviours$3 = bData => bData.list;
  2397. const getData$2 = bData => bData.data;
  2398. const byInnerKey = (data, tuple) => {
  2399. const r = {};
  2400. each(data, (detail, key) => {
  2401. each(detail, (value, indexKey) => {
  2402. const chain = get$g(r, indexKey).getOr([]);
  2403. r[indexKey] = chain.concat([tuple(key, value)]);
  2404. });
  2405. });
  2406. return r;
  2407. };
  2408. const nu$7 = s => ({
  2409. classes: isUndefined(s.classes) ? [] : s.classes,
  2410. attributes: isUndefined(s.attributes) ? {} : s.attributes,
  2411. styles: isUndefined(s.styles) ? {} : s.styles
  2412. });
  2413. const merge = (defnA, mod) => ({
  2414. ...defnA,
  2415. attributes: {
  2416. ...defnA.attributes,
  2417. ...mod.attributes
  2418. },
  2419. styles: {
  2420. ...defnA.styles,
  2421. ...mod.styles
  2422. },
  2423. classes: defnA.classes.concat(mod.classes)
  2424. });
  2425. const combine$2 = (info, baseMod, behaviours, base) => {
  2426. const modsByBehaviour = { ...baseMod };
  2427. each$1(behaviours, behaviour => {
  2428. modsByBehaviour[behaviour.name()] = behaviour.exhibit(info, base);
  2429. });
  2430. const byAspect = byInnerKey(modsByBehaviour, (name, modification) => ({
  2431. name,
  2432. modification
  2433. }));
  2434. const combineObjects = objects => foldr(objects, (b, a) => ({
  2435. ...a.modification,
  2436. ...b
  2437. }), {});
  2438. const combinedClasses = foldr(byAspect.classes, (b, a) => a.modification.concat(b), []);
  2439. const combinedAttributes = combineObjects(byAspect.attributes);
  2440. const combinedStyles = combineObjects(byAspect.styles);
  2441. return nu$7({
  2442. classes: combinedClasses,
  2443. attributes: combinedAttributes,
  2444. styles: combinedStyles
  2445. });
  2446. };
  2447. const sortKeys = (label, keyName, array, order) => {
  2448. try {
  2449. const sorted = sort(array, (a, b) => {
  2450. const aKey = a[keyName];
  2451. const bKey = b[keyName];
  2452. const aIndex = order.indexOf(aKey);
  2453. const bIndex = order.indexOf(bKey);
  2454. if (aIndex === -1) {
  2455. throw new Error('The ordering for ' + label + ' does not have an entry for ' + aKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
  2456. }
  2457. if (bIndex === -1) {
  2458. throw new Error('The ordering for ' + label + ' does not have an entry for ' + bKey + '.\nOrder specified: ' + JSON.stringify(order, null, 2));
  2459. }
  2460. if (aIndex < bIndex) {
  2461. return -1;
  2462. } else if (bIndex < aIndex) {
  2463. return 1;
  2464. } else {
  2465. return 0;
  2466. }
  2467. });
  2468. return Result.value(sorted);
  2469. } catch (err) {
  2470. return Result.error([err]);
  2471. }
  2472. };
  2473. const uncurried = (handler, purpose) => ({
  2474. handler,
  2475. purpose
  2476. });
  2477. const curried = (handler, purpose) => ({
  2478. cHandler: handler,
  2479. purpose
  2480. });
  2481. const curryArgs = (descHandler, extraArgs) => curried(curry.apply(undefined, [descHandler.handler].concat(extraArgs)), descHandler.purpose);
  2482. const getCurried = descHandler => descHandler.cHandler;
  2483. const behaviourTuple = (name, handler) => ({
  2484. name,
  2485. handler
  2486. });
  2487. const nameToHandlers = (behaviours, info) => {
  2488. const r = {};
  2489. each$1(behaviours, behaviour => {
  2490. r[behaviour.name()] = behaviour.handlers(info);
  2491. });
  2492. return r;
  2493. };
  2494. const groupByEvents = (info, behaviours, base) => {
  2495. const behaviourEvents = {
  2496. ...base,
  2497. ...nameToHandlers(behaviours, info)
  2498. };
  2499. return byInnerKey(behaviourEvents, behaviourTuple);
  2500. };
  2501. const combine$1 = (info, eventOrder, behaviours, base) => {
  2502. const byEventName = groupByEvents(info, behaviours, base);
  2503. return combineGroups(byEventName, eventOrder);
  2504. };
  2505. const assemble = rawHandler => {
  2506. const handler = read$2(rawHandler);
  2507. return (component, simulatedEvent, ...rest) => {
  2508. const args = [
  2509. component,
  2510. simulatedEvent
  2511. ].concat(rest);
  2512. if (handler.abort.apply(undefined, args)) {
  2513. simulatedEvent.stop();
  2514. } else if (handler.can.apply(undefined, args)) {
  2515. handler.run.apply(undefined, args);
  2516. }
  2517. };
  2518. };
  2519. 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)]);
  2520. const fuse = (tuples, eventOrder, eventName) => {
  2521. const order = eventOrder[eventName];
  2522. if (!order) {
  2523. return missingOrderError(eventName, tuples);
  2524. } else {
  2525. return sortKeys('Event: ' + eventName, 'name', tuples, order).map(sortedTuples => {
  2526. const handlers = map$2(sortedTuples, tuple => tuple.handler);
  2527. return fuse$1(handlers);
  2528. });
  2529. }
  2530. };
  2531. const combineGroups = (byEventName, eventOrder) => {
  2532. const r = mapToArray(byEventName, (tuples, eventName) => {
  2533. const combined = tuples.length === 1 ? Result.value(tuples[0].handler) : fuse(tuples, eventOrder, eventName);
  2534. return combined.map(handler => {
  2535. const assembled = assemble(handler);
  2536. const purpose = tuples.length > 1 ? filter$2(eventOrder[eventName], o => exists(tuples, t => t.name === o)).join(' > ') : tuples[0].name;
  2537. return wrap$1(eventName, uncurried(assembled, purpose));
  2538. });
  2539. });
  2540. return consolidate(r, {});
  2541. };
  2542. const baseBehaviour = 'alloy.base.behaviour';
  2543. const schema$z = objOf([
  2544. field$1('dom', 'dom', required$2(), objOf([
  2545. required$1('tag'),
  2546. defaulted('styles', {}),
  2547. defaulted('classes', []),
  2548. defaulted('attributes', {}),
  2549. option$3('value'),
  2550. option$3('innerHtml')
  2551. ])),
  2552. required$1('components'),
  2553. required$1('uid'),
  2554. defaulted('events', {}),
  2555. defaulted('apis', {}),
  2556. field$1('eventOrder', 'eventOrder', mergeWith({
  2557. [execute$5()]: [
  2558. 'disabling',
  2559. baseBehaviour,
  2560. 'toggling',
  2561. 'typeaheadevents'
  2562. ],
  2563. [focus$4()]: [
  2564. baseBehaviour,
  2565. 'focusing',
  2566. 'keying'
  2567. ],
  2568. [systemInit()]: [
  2569. baseBehaviour,
  2570. 'disabling',
  2571. 'toggling',
  2572. 'representing'
  2573. ],
  2574. [input()]: [
  2575. baseBehaviour,
  2576. 'representing',
  2577. 'streaming',
  2578. 'invalidating'
  2579. ],
  2580. [detachedFromDom()]: [
  2581. baseBehaviour,
  2582. 'representing',
  2583. 'item-events',
  2584. 'tooltipping'
  2585. ],
  2586. [mousedown()]: [
  2587. 'focusing',
  2588. baseBehaviour,
  2589. 'item-type-events'
  2590. ],
  2591. [touchstart()]: [
  2592. 'focusing',
  2593. baseBehaviour,
  2594. 'item-type-events'
  2595. ],
  2596. [mouseover()]: [
  2597. 'item-type-events',
  2598. 'tooltipping'
  2599. ],
  2600. [receive()]: [
  2601. 'receiving',
  2602. 'reflecting',
  2603. 'tooltipping'
  2604. ]
  2605. }), anyValue()),
  2606. option$3('domModification')
  2607. ]);
  2608. const toInfo = spec => asRaw('custom.definition', schema$z, spec);
  2609. const toDefinition = detail => ({
  2610. ...detail.dom,
  2611. uid: detail.uid,
  2612. domChildren: map$2(detail.components, comp => comp.element)
  2613. });
  2614. const toModification = detail => detail.domModification.fold(() => nu$7({}), nu$7);
  2615. const toEvents = info => info.events;
  2616. const read = (element, attr) => {
  2617. const value = get$f(element, attr);
  2618. return value === undefined || value === '' ? [] : value.split(' ');
  2619. };
  2620. const add$4 = (element, attr, id) => {
  2621. const old = read(element, attr);
  2622. const nu = old.concat([id]);
  2623. set$9(element, attr, nu.join(' '));
  2624. return true;
  2625. };
  2626. const remove$4 = (element, attr, id) => {
  2627. const nu = filter$2(read(element, attr), v => v !== id);
  2628. if (nu.length > 0) {
  2629. set$9(element, attr, nu.join(' '));
  2630. } else {
  2631. remove$7(element, attr);
  2632. }
  2633. return false;
  2634. };
  2635. const supports = element => element.dom.classList !== undefined;
  2636. const get$8 = element => read(element, 'class');
  2637. const add$3 = (element, clazz) => add$4(element, 'class', clazz);
  2638. const remove$3 = (element, clazz) => remove$4(element, 'class', clazz);
  2639. const add$2 = (element, clazz) => {
  2640. if (supports(element)) {
  2641. element.dom.classList.add(clazz);
  2642. } else {
  2643. add$3(element, clazz);
  2644. }
  2645. };
  2646. const cleanClass = element => {
  2647. const classList = supports(element) ? element.dom.classList : get$8(element);
  2648. if (classList.length === 0) {
  2649. remove$7(element, 'class');
  2650. }
  2651. };
  2652. const remove$2 = (element, clazz) => {
  2653. if (supports(element)) {
  2654. const classList = element.dom.classList;
  2655. classList.remove(clazz);
  2656. } else {
  2657. remove$3(element, clazz);
  2658. }
  2659. cleanClass(element);
  2660. };
  2661. const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
  2662. const add$1 = (element, classes) => {
  2663. each$1(classes, x => {
  2664. add$2(element, x);
  2665. });
  2666. };
  2667. const remove$1 = (element, classes) => {
  2668. each$1(classes, x => {
  2669. remove$2(element, x);
  2670. });
  2671. };
  2672. const hasAll = (element, classes) => forall(classes, clazz => has(element, clazz));
  2673. const getNative = element => {
  2674. const classList = element.dom.classList;
  2675. const r = new Array(classList.length);
  2676. for (let i = 0; i < classList.length; i++) {
  2677. const item = classList.item(i);
  2678. if (item !== null) {
  2679. r[i] = item;
  2680. }
  2681. }
  2682. return r;
  2683. };
  2684. const get$7 = element => supports(element) ? getNative(element) : get$8(element);
  2685. const get$6 = element => element.dom.value;
  2686. const set$5 = (element, value) => {
  2687. if (value === undefined) {
  2688. throw new Error('Value.set was undefined');
  2689. }
  2690. element.dom.value = value;
  2691. };
  2692. const determineObsoleted = (parent, index, oldObsoleted) => {
  2693. const newObsoleted = child$2(parent, index);
  2694. return newObsoleted.map(newObs => {
  2695. const elemChanged = oldObsoleted.exists(o => !eq(o, newObs));
  2696. if (elemChanged) {
  2697. const oldTag = oldObsoleted.map(name$3).getOr('span');
  2698. const marker = SugarElement.fromTag(oldTag);
  2699. before$1(newObs, marker);
  2700. return marker;
  2701. } else {
  2702. return newObs;
  2703. }
  2704. });
  2705. };
  2706. const ensureInDom = (parent, child, obsoleted) => {
  2707. obsoleted.fold(() => append$2(parent, child), obs => {
  2708. if (!eq(obs, child)) {
  2709. before$1(obs, child);
  2710. remove$5(obs);
  2711. }
  2712. });
  2713. };
  2714. const patchChildrenWith = (parent, nu, f) => {
  2715. const builtChildren = map$2(nu, f);
  2716. const currentChildren = children(parent);
  2717. each$1(currentChildren.slice(builtChildren.length), remove$5);
  2718. return builtChildren;
  2719. };
  2720. const patchSpecChild = (parent, index, spec, build) => {
  2721. const oldObsoleted = child$2(parent, index);
  2722. const childComp = build(spec, oldObsoleted);
  2723. const obsoleted = determineObsoleted(parent, index, oldObsoleted);
  2724. ensureInDom(parent, childComp.element, obsoleted);
  2725. return childComp;
  2726. };
  2727. const patchSpecChildren = (parent, specs, build) => patchChildrenWith(parent, specs, (spec, index) => patchSpecChild(parent, index, spec, build));
  2728. const patchDomChildren = (parent, nodes) => patchChildrenWith(parent, nodes, (node, index) => {
  2729. const optObsoleted = child$2(parent, index);
  2730. ensureInDom(parent, node, optObsoleted);
  2731. return node;
  2732. });
  2733. const diffKeyValueSet = (newObj, oldObj) => {
  2734. const newKeys = keys(newObj);
  2735. const oldKeys = keys(oldObj);
  2736. const toRemove = difference(oldKeys, newKeys);
  2737. const toSet = bifilter(newObj, (v, k) => {
  2738. return !has$2(oldObj, k) || v !== oldObj[k];
  2739. }).t;
  2740. return {
  2741. toRemove,
  2742. toSet
  2743. };
  2744. };
  2745. const reconcileToDom = (definition, obsoleted) => {
  2746. const {
  2747. class: clazz,
  2748. style,
  2749. ...existingAttributes
  2750. } = clone$1(obsoleted);
  2751. const {
  2752. toSet: attrsToSet,
  2753. toRemove: attrsToRemove
  2754. } = diffKeyValueSet(definition.attributes, existingAttributes);
  2755. const updateAttrs = () => {
  2756. each$1(attrsToRemove, a => remove$7(obsoleted, a));
  2757. setAll$1(obsoleted, attrsToSet);
  2758. };
  2759. const existingStyles = getAllRaw(obsoleted);
  2760. const {
  2761. toSet: stylesToSet,
  2762. toRemove: stylesToRemove
  2763. } = diffKeyValueSet(definition.styles, existingStyles);
  2764. const updateStyles = () => {
  2765. each$1(stylesToRemove, s => remove$6(obsoleted, s));
  2766. setAll(obsoleted, stylesToSet);
  2767. };
  2768. const existingClasses = get$7(obsoleted);
  2769. const classesToRemove = difference(existingClasses, definition.classes);
  2770. const classesToAdd = difference(definition.classes, existingClasses);
  2771. const updateClasses = () => {
  2772. add$1(obsoleted, classesToAdd);
  2773. remove$1(obsoleted, classesToRemove);
  2774. };
  2775. const updateHtml = html => {
  2776. set$6(obsoleted, html);
  2777. };
  2778. const updateChildren = () => {
  2779. const children = definition.domChildren;
  2780. patchDomChildren(obsoleted, children);
  2781. };
  2782. const updateValue = () => {
  2783. const valueElement = obsoleted;
  2784. const value = definition.value.getOrUndefined();
  2785. if (value !== get$6(valueElement)) {
  2786. set$5(valueElement, value !== null && value !== void 0 ? value : '');
  2787. }
  2788. };
  2789. updateAttrs();
  2790. updateClasses();
  2791. updateStyles();
  2792. definition.innerHtml.fold(updateChildren, updateHtml);
  2793. updateValue();
  2794. return obsoleted;
  2795. };
  2796. const introduceToDom = definition => {
  2797. const subject = SugarElement.fromTag(definition.tag);
  2798. setAll$1(subject, definition.attributes);
  2799. add$1(subject, definition.classes);
  2800. setAll(subject, definition.styles);
  2801. definition.innerHtml.each(html => set$6(subject, html));
  2802. const children = definition.domChildren;
  2803. append$1(subject, children);
  2804. definition.value.each(value => {
  2805. set$5(subject, value);
  2806. });
  2807. return subject;
  2808. };
  2809. const attemptPatch = (definition, obsoleted) => {
  2810. try {
  2811. const e = reconcileToDom(definition, obsoleted);
  2812. return Optional.some(e);
  2813. } catch (err) {
  2814. return Optional.none();
  2815. }
  2816. };
  2817. const hasMixedChildren = definition => definition.innerHtml.isSome() && definition.domChildren.length > 0;
  2818. const renderToDom = (definition, optObsoleted) => {
  2819. const canBePatched = candidate => name$3(candidate) === definition.tag && !hasMixedChildren(definition) && !isPremade(candidate);
  2820. const elem = optObsoleted.filter(canBePatched).bind(obsoleted => attemptPatch(definition, obsoleted)).getOrThunk(() => introduceToDom(definition));
  2821. writeOnly(elem, definition.uid);
  2822. return elem;
  2823. };
  2824. const getBehaviours$2 = spec => {
  2825. const behaviours = get$g(spec, 'behaviours').getOr({});
  2826. return bind$3(keys(behaviours), name => {
  2827. const behaviour = behaviours[name];
  2828. return isNonNullable(behaviour) ? [behaviour.me] : [];
  2829. });
  2830. };
  2831. const generateFrom = (spec, all) => generateFrom$1(spec, all);
  2832. const generate$4 = spec => {
  2833. const all = getBehaviours$2(spec);
  2834. return generateFrom(spec, all);
  2835. };
  2836. const getDomDefinition = (info, bList, bData) => {
  2837. const definition = toDefinition(info);
  2838. const infoModification = toModification(info);
  2839. const baseModification = { 'alloy.base.modification': infoModification };
  2840. const modification = bList.length > 0 ? combine$2(bData, baseModification, bList, definition) : infoModification;
  2841. return merge(definition, modification);
  2842. };
  2843. const getEvents = (info, bList, bData) => {
  2844. const baseEvents = { 'alloy.base.behaviour': toEvents(info) };
  2845. return combine$1(bData, info.eventOrder, bList, baseEvents).getOrDie();
  2846. };
  2847. const build$2 = (spec, obsoleted) => {
  2848. const getMe = () => me;
  2849. const systemApi = Cell(singleton$1);
  2850. const info = getOrDie(toInfo(spec));
  2851. const bBlob = generate$4(spec);
  2852. const bList = getBehaviours$3(bBlob);
  2853. const bData = getData$2(bBlob);
  2854. const modDefinition = getDomDefinition(info, bList, bData);
  2855. const item = renderToDom(modDefinition, obsoleted);
  2856. const events = getEvents(info, bList, bData);
  2857. const subcomponents = Cell(info.components);
  2858. const connect = newApi => {
  2859. systemApi.set(newApi);
  2860. };
  2861. const disconnect = () => {
  2862. systemApi.set(NoContextApi(getMe));
  2863. };
  2864. const syncComponents = () => {
  2865. const children$1 = children(item);
  2866. const subs = bind$3(children$1, child => systemApi.get().getByDom(child).fold(() => [], pure$2));
  2867. subcomponents.set(subs);
  2868. };
  2869. const config = behaviour => {
  2870. const b = bData;
  2871. const f = isFunction(b[behaviour.name()]) ? b[behaviour.name()] : () => {
  2872. throw new Error('Could not find ' + behaviour.name() + ' in ' + JSON.stringify(spec, null, 2));
  2873. };
  2874. return f();
  2875. };
  2876. const hasConfigured = behaviour => isFunction(bData[behaviour.name()]);
  2877. const getApis = () => info.apis;
  2878. const readState = behaviourName => bData[behaviourName]().map(b => b.state.readState()).getOr('not enabled');
  2879. const me = {
  2880. uid: spec.uid,
  2881. getSystem: systemApi.get,
  2882. config,
  2883. hasConfigured,
  2884. spec,
  2885. readState,
  2886. getApis,
  2887. connect,
  2888. disconnect,
  2889. element: item,
  2890. syncComponents,
  2891. components: subcomponents.get,
  2892. events
  2893. };
  2894. return me;
  2895. };
  2896. const buildSubcomponents = (spec, obsoleted) => {
  2897. const components = get$g(spec, 'components').getOr([]);
  2898. return obsoleted.fold(() => map$2(components, build$1), obs => map$2(components, (c, i) => {
  2899. return buildOrPatch(c, child$2(obs, i));
  2900. }));
  2901. };
  2902. const buildFromSpec = (userSpec, obsoleted) => {
  2903. const {
  2904. events: specEvents,
  2905. ...spec
  2906. } = make$8(userSpec);
  2907. const components = buildSubcomponents(spec, obsoleted);
  2908. const completeSpec = {
  2909. ...spec,
  2910. events: {
  2911. ...DefaultEvents,
  2912. ...specEvents
  2913. },
  2914. components
  2915. };
  2916. return Result.value(build$2(completeSpec, obsoleted));
  2917. };
  2918. const text$1 = textContent => {
  2919. const element = SugarElement.fromText(textContent);
  2920. return external$1({ element });
  2921. };
  2922. const external$1 = spec => {
  2923. const extSpec = asRawOrDie$1('external.component', objOfOnly([
  2924. required$1('element'),
  2925. option$3('uid')
  2926. ]), spec);
  2927. const systemApi = Cell(NoContextApi());
  2928. const connect = newApi => {
  2929. systemApi.set(newApi);
  2930. };
  2931. const disconnect = () => {
  2932. systemApi.set(NoContextApi(() => me));
  2933. };
  2934. const uid = extSpec.uid.getOrThunk(() => generate$5('external'));
  2935. writeOnly(extSpec.element, uid);
  2936. const me = {
  2937. uid,
  2938. getSystem: systemApi.get,
  2939. config: Optional.none,
  2940. hasConfigured: never,
  2941. connect,
  2942. disconnect,
  2943. getApis: () => ({}),
  2944. element: extSpec.element,
  2945. spec,
  2946. readState: constant$1('No state'),
  2947. syncComponents: noop,
  2948. components: constant$1([]),
  2949. events: {}
  2950. };
  2951. return premade$1(me);
  2952. };
  2953. const uids = generate$5;
  2954. const isSketchSpec$1 = spec => has$2(spec, 'uid');
  2955. const buildOrPatch = (spec, obsoleted) => getPremade(spec).getOrThunk(() => {
  2956. const userSpecWithUid = isSketchSpec$1(spec) ? spec : {
  2957. uid: uids(''),
  2958. ...spec
  2959. };
  2960. return buildFromSpec(userSpecWithUid, obsoleted).getOrDie();
  2961. });
  2962. const build$1 = spec => buildOrPatch(spec, Optional.none());
  2963. const premade = premade$1;
  2964. var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
  2965. if (is(scope, a)) {
  2966. return Optional.some(scope);
  2967. } else if (isFunction(isRoot) && isRoot(scope)) {
  2968. return Optional.none();
  2969. } else {
  2970. return ancestor(scope, a, isRoot);
  2971. }
  2972. };
  2973. const ancestor$1 = (scope, predicate, isRoot) => {
  2974. let element = scope.dom;
  2975. const stop = isFunction(isRoot) ? isRoot : never;
  2976. while (element.parentNode) {
  2977. element = element.parentNode;
  2978. const el = SugarElement.fromDom(element);
  2979. if (predicate(el)) {
  2980. return Optional.some(el);
  2981. } else if (stop(el)) {
  2982. break;
  2983. }
  2984. }
  2985. return Optional.none();
  2986. };
  2987. const closest$3 = (scope, predicate, isRoot) => {
  2988. const is = (s, test) => test(s);
  2989. return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
  2990. };
  2991. const child$1 = (scope, predicate) => {
  2992. const pred = node => predicate(SugarElement.fromDom(node));
  2993. const result = find$5(scope.dom.childNodes, pred);
  2994. return result.map(SugarElement.fromDom);
  2995. };
  2996. const descendant$1 = (scope, predicate) => {
  2997. const descend = node => {
  2998. for (let i = 0; i < node.childNodes.length; i++) {
  2999. const child = SugarElement.fromDom(node.childNodes[i]);
  3000. if (predicate(child)) {
  3001. return Optional.some(child);
  3002. }
  3003. const res = descend(node.childNodes[i]);
  3004. if (res.isSome()) {
  3005. return res;
  3006. }
  3007. }
  3008. return Optional.none();
  3009. };
  3010. return descend(scope.dom);
  3011. };
  3012. const closest$2 = (scope, predicate, isRoot) => closest$3(scope, predicate, isRoot).isSome();
  3013. const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is(e, selector), isRoot);
  3014. const child = (scope, selector) => child$1(scope, e => is(e, selector));
  3015. const descendant = (scope, selector) => one(selector, scope);
  3016. const closest$1 = (scope, selector, isRoot) => {
  3017. const is$1 = (element, selector) => is(element, selector);
  3018. return ClosestOrAncestor(is$1, ancestor, scope, selector, isRoot);
  3019. };
  3020. const attribute = 'aria-controls';
  3021. const find$1 = queryElem => {
  3022. const dependent = closest$3(queryElem, elem => {
  3023. if (!isElement$1(elem)) {
  3024. return false;
  3025. }
  3026. const id = get$f(elem, 'id');
  3027. return id !== undefined && id.indexOf(attribute) > -1;
  3028. });
  3029. return dependent.bind(dep => {
  3030. const id = get$f(dep, 'id');
  3031. const dos = getRootNode(dep);
  3032. return descendant(dos, `[${ attribute }="${ id }"]`);
  3033. });
  3034. };
  3035. const manager = () => {
  3036. const ariaId = generate$6(attribute);
  3037. const link = elem => {
  3038. set$9(elem, attribute, ariaId);
  3039. };
  3040. const unlink = elem => {
  3041. remove$7(elem, attribute);
  3042. };
  3043. return {
  3044. id: ariaId,
  3045. link,
  3046. unlink
  3047. };
  3048. };
  3049. const isAriaPartOf = (component, queryElem) => find$1(queryElem).exists(owner => isPartOf$1(component, owner));
  3050. const isPartOf$1 = (component, queryElem) => closest$2(queryElem, el => eq(el, component.element), never) || isAriaPartOf(component, queryElem);
  3051. const unknown = 'unknown';
  3052. var EventConfiguration;
  3053. (function (EventConfiguration) {
  3054. EventConfiguration[EventConfiguration['STOP'] = 0] = 'STOP';
  3055. EventConfiguration[EventConfiguration['NORMAL'] = 1] = 'NORMAL';
  3056. EventConfiguration[EventConfiguration['LOGGING'] = 2] = 'LOGGING';
  3057. }(EventConfiguration || (EventConfiguration = {})));
  3058. const eventConfig = Cell({});
  3059. const makeEventLogger = (eventName, initialTarget) => {
  3060. const sequence = [];
  3061. const startTime = new Date().getTime();
  3062. return {
  3063. logEventCut: (_name, target, purpose) => {
  3064. sequence.push({
  3065. outcome: 'cut',
  3066. target,
  3067. purpose
  3068. });
  3069. },
  3070. logEventStopped: (_name, target, purpose) => {
  3071. sequence.push({
  3072. outcome: 'stopped',
  3073. target,
  3074. purpose
  3075. });
  3076. },
  3077. logNoParent: (_name, target, purpose) => {
  3078. sequence.push({
  3079. outcome: 'no-parent',
  3080. target,
  3081. purpose
  3082. });
  3083. },
  3084. logEventNoHandlers: (_name, target) => {
  3085. sequence.push({
  3086. outcome: 'no-handlers-left',
  3087. target
  3088. });
  3089. },
  3090. logEventResponse: (_name, target, purpose) => {
  3091. sequence.push({
  3092. outcome: 'response',
  3093. purpose,
  3094. target
  3095. });
  3096. },
  3097. write: () => {
  3098. const finishTime = new Date().getTime();
  3099. if (contains$2([
  3100. 'mousemove',
  3101. 'mouseover',
  3102. 'mouseout',
  3103. systemInit()
  3104. ], eventName)) {
  3105. return;
  3106. }
  3107. console.log(eventName, {
  3108. event: eventName,
  3109. time: finishTime - startTime,
  3110. target: initialTarget.dom,
  3111. sequence: map$2(sequence, s => {
  3112. if (!contains$2([
  3113. 'cut',
  3114. 'stopped',
  3115. 'response'
  3116. ], s.outcome)) {
  3117. return s.outcome;
  3118. } else {
  3119. return '{' + s.purpose + '} ' + s.outcome + ' at (' + element(s.target) + ')';
  3120. }
  3121. })
  3122. });
  3123. }
  3124. };
  3125. };
  3126. const processEvent = (eventName, initialTarget, f) => {
  3127. const status = get$g(eventConfig.get(), eventName).orThunk(() => {
  3128. const patterns = keys(eventConfig.get());
  3129. return findMap(patterns, p => eventName.indexOf(p) > -1 ? Optional.some(eventConfig.get()[p]) : Optional.none());
  3130. }).getOr(EventConfiguration.NORMAL);
  3131. switch (status) {
  3132. case EventConfiguration.NORMAL:
  3133. return f(noLogger());
  3134. case EventConfiguration.LOGGING: {
  3135. const logger = makeEventLogger(eventName, initialTarget);
  3136. const output = f(logger);
  3137. logger.write();
  3138. return output;
  3139. }
  3140. case EventConfiguration.STOP:
  3141. return true;
  3142. }
  3143. };
  3144. const path = [
  3145. 'alloy/data/Fields',
  3146. 'alloy/debugging/Debugging'
  3147. ];
  3148. const getTrace = () => {
  3149. const err = new Error();
  3150. if (err.stack !== undefined) {
  3151. const lines = err.stack.split('\n');
  3152. return find$5(lines, line => line.indexOf('alloy') > 0 && !exists(path, p => line.indexOf(p) > -1)).getOr(unknown);
  3153. } else {
  3154. return unknown;
  3155. }
  3156. };
  3157. const ignoreEvent = {
  3158. logEventCut: noop,
  3159. logEventStopped: noop,
  3160. logNoParent: noop,
  3161. logEventNoHandlers: noop,
  3162. logEventResponse: noop,
  3163. write: noop
  3164. };
  3165. const monitorEvent = (eventName, initialTarget, f) => processEvent(eventName, initialTarget, f);
  3166. const noLogger = constant$1(ignoreEvent);
  3167. const menuFields = constant$1([
  3168. required$1('menu'),
  3169. required$1('selectedMenu')
  3170. ]);
  3171. const itemFields = constant$1([
  3172. required$1('item'),
  3173. required$1('selectedItem')
  3174. ]);
  3175. constant$1(objOf(itemFields().concat(menuFields())));
  3176. const itemSchema$3 = constant$1(objOf(itemFields()));
  3177. const _initSize = requiredObjOf('initSize', [
  3178. required$1('numColumns'),
  3179. required$1('numRows')
  3180. ]);
  3181. const itemMarkers = () => requiredOf('markers', itemSchema$3());
  3182. const tieredMenuMarkers = () => requiredObjOf('markers', [required$1('backgroundMenu')].concat(menuFields()).concat(itemFields()));
  3183. const markers$1 = required => requiredObjOf('markers', map$2(required, required$1));
  3184. const onPresenceHandler = (label, fieldName, presence) => {
  3185. getTrace();
  3186. return field$1(fieldName, fieldName, presence, valueOf(f => Result.value((...args) => {
  3187. return f.apply(undefined, args);
  3188. })));
  3189. };
  3190. const onHandler = fieldName => onPresenceHandler('onHandler', fieldName, defaulted$1(noop));
  3191. const onKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, defaulted$1(Optional.none));
  3192. const onStrictHandler = fieldName => onPresenceHandler('onHandler', fieldName, required$2());
  3193. const onStrictKeyboardHandler = fieldName => onPresenceHandler('onKeyboardHandler', fieldName, required$2());
  3194. const output$1 = (name, value) => customField(name, constant$1(value));
  3195. const snapshot = name => customField(name, identity);
  3196. const initSize = constant$1(_initSize);
  3197. const nu$6 = (x, y, bubble, direction, placement, boundsRestriction, labelPrefix, alwaysFit = false) => ({
  3198. x,
  3199. y,
  3200. bubble,
  3201. direction,
  3202. placement,
  3203. restriction: boundsRestriction,
  3204. label: `${ labelPrefix }-${ placement }`,
  3205. alwaysFit
  3206. });
  3207. const adt$a = Adt.generate([
  3208. { southeast: [] },
  3209. { southwest: [] },
  3210. { northeast: [] },
  3211. { northwest: [] },
  3212. { south: [] },
  3213. { north: [] },
  3214. { east: [] },
  3215. { west: [] }
  3216. ]);
  3217. const cata$2 = (subject, southeast, southwest, northeast, northwest, south, north, east, west) => subject.fold(southeast, southwest, northeast, northwest, south, north, east, west);
  3218. const cataVertical = (subject, south, middle, north) => subject.fold(south, south, north, north, south, north, middle, middle);
  3219. const cataHorizontal = (subject, east, middle, west) => subject.fold(east, west, east, west, middle, middle, east, west);
  3220. const southeast$3 = adt$a.southeast;
  3221. const southwest$3 = adt$a.southwest;
  3222. const northeast$3 = adt$a.northeast;
  3223. const northwest$3 = adt$a.northwest;
  3224. const south$3 = adt$a.south;
  3225. const north$3 = adt$a.north;
  3226. const east$3 = adt$a.east;
  3227. const west$3 = adt$a.west;
  3228. const cycleBy = (value, delta, min, max) => {
  3229. const r = value + delta;
  3230. if (r > max) {
  3231. return min;
  3232. } else if (r < min) {
  3233. return max;
  3234. } else {
  3235. return r;
  3236. }
  3237. };
  3238. const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
  3239. const getRestriction = (anchor, restriction) => {
  3240. switch (restriction) {
  3241. case 1:
  3242. return anchor.x;
  3243. case 0:
  3244. return anchor.x + anchor.width;
  3245. case 2:
  3246. return anchor.y;
  3247. case 3:
  3248. return anchor.y + anchor.height;
  3249. }
  3250. };
  3251. const boundsRestriction = (anchor, restrictions) => mapToObject([
  3252. 'left',
  3253. 'right',
  3254. 'top',
  3255. 'bottom'
  3256. ], dir => get$g(restrictions, dir).map(restriction => getRestriction(anchor, restriction)));
  3257. const adjustBounds = (bounds$1, restriction, bubbleOffset) => {
  3258. const applyRestriction = (dir, current) => restriction[dir].map(pos => {
  3259. const isVerticalAxis = dir === 'top' || dir === 'bottom';
  3260. const offset = isVerticalAxis ? bubbleOffset.top : bubbleOffset.left;
  3261. const comparator = dir === 'left' || dir === 'top' ? Math.max : Math.min;
  3262. const newPos = comparator(pos, current) + offset;
  3263. return isVerticalAxis ? clamp(newPos, bounds$1.y, bounds$1.bottom) : clamp(newPos, bounds$1.x, bounds$1.right);
  3264. }).getOr(current);
  3265. const adjustedLeft = applyRestriction('left', bounds$1.x);
  3266. const adjustedTop = applyRestriction('top', bounds$1.y);
  3267. const adjustedRight = applyRestriction('right', bounds$1.right);
  3268. const adjustedBottom = applyRestriction('bottom', bounds$1.bottom);
  3269. return bounds(adjustedLeft, adjustedTop, adjustedRight - adjustedLeft, adjustedBottom - adjustedTop);
  3270. };
  3271. const labelPrefix$2 = 'layout';
  3272. const eastX$1 = anchor => anchor.x;
  3273. const middleX$1 = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
  3274. const westX$1 = (anchor, element) => anchor.x + anchor.width - element.width;
  3275. const northY$2 = (anchor, element) => anchor.y - element.height;
  3276. const southY$2 = anchor => anchor.y + anchor.height;
  3277. const centreY$1 = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
  3278. const eastEdgeX$1 = anchor => anchor.x + anchor.width;
  3279. const westEdgeX$1 = (anchor, element) => anchor.x - element.width;
  3280. const southeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), southY$2(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
  3281. left: 1,
  3282. top: 3
  3283. }), labelPrefix$2);
  3284. const southwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), southY$2(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
  3285. right: 0,
  3286. top: 3
  3287. }), labelPrefix$2);
  3288. const northeast$2 = (anchor, element, bubbles) => nu$6(eastX$1(anchor), northY$2(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
  3289. left: 1,
  3290. bottom: 2
  3291. }), labelPrefix$2);
  3292. const northwest$2 = (anchor, element, bubbles) => nu$6(westX$1(anchor, element), northY$2(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
  3293. right: 0,
  3294. bottom: 2
  3295. }), labelPrefix$2);
  3296. 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);
  3297. 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);
  3298. 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);
  3299. 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);
  3300. const all$1 = () => [
  3301. southeast$2,
  3302. southwest$2,
  3303. northeast$2,
  3304. northwest$2,
  3305. south$2,
  3306. north$2,
  3307. east$2,
  3308. west$2
  3309. ];
  3310. const allRtl$1 = () => [
  3311. southwest$2,
  3312. southeast$2,
  3313. northwest$2,
  3314. northeast$2,
  3315. south$2,
  3316. north$2,
  3317. east$2,
  3318. west$2
  3319. ];
  3320. const aboveOrBelow = () => [
  3321. northeast$2,
  3322. northwest$2,
  3323. southeast$2,
  3324. southwest$2,
  3325. north$2,
  3326. south$2
  3327. ];
  3328. const aboveOrBelowRtl = () => [
  3329. northwest$2,
  3330. northeast$2,
  3331. southwest$2,
  3332. southeast$2,
  3333. north$2,
  3334. south$2
  3335. ];
  3336. const belowOrAbove = () => [
  3337. southeast$2,
  3338. southwest$2,
  3339. northeast$2,
  3340. northwest$2,
  3341. south$2,
  3342. north$2
  3343. ];
  3344. const belowOrAboveRtl = () => [
  3345. southwest$2,
  3346. southeast$2,
  3347. northwest$2,
  3348. northeast$2,
  3349. south$2,
  3350. north$2
  3351. ];
  3352. const chooseChannels = (channels, message) => message.universal ? channels : filter$2(channels, ch => contains$2(message.channels, ch));
  3353. const events$h = receiveConfig => derive$2([run$1(receive(), (component, message) => {
  3354. const channelMap = receiveConfig.channels;
  3355. const channels = keys(channelMap);
  3356. const receivingData = message;
  3357. const targetChannels = chooseChannels(channels, receivingData);
  3358. each$1(targetChannels, ch => {
  3359. const channelInfo = channelMap[ch];
  3360. const channelSchema = channelInfo.schema;
  3361. const data = asRawOrDie$1('channel[' + ch + '] data\nReceiver: ' + element(component.element), channelSchema, receivingData.data);
  3362. channelInfo.onReceive(component, data);
  3363. });
  3364. })]);
  3365. var ActiveReceiving = /*#__PURE__*/Object.freeze({
  3366. __proto__: null,
  3367. events: events$h
  3368. });
  3369. var ReceivingSchema = [requiredOf('channels', setOf(Result.value, objOfOnly([
  3370. onStrictHandler('onReceive'),
  3371. defaulted('schema', anyValue())
  3372. ])))];
  3373. const executeEvent = (bConfig, bState, executor) => runOnExecute$1(component => {
  3374. executor(component, bConfig, bState);
  3375. });
  3376. const loadEvent = (bConfig, bState, f) => runOnInit((component, _simulatedEvent) => {
  3377. f(component, bConfig, bState);
  3378. });
  3379. const create$4 = (schema, name, active, apis, extra, state) => {
  3380. const configSchema = objOfOnly(schema);
  3381. const schemaSchema = optionObjOf(name, [optionObjOfOnly('config', schema)]);
  3382. return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
  3383. };
  3384. const createModes$1 = (modes, name, active, apis, extra, state) => {
  3385. const configSchema = modes;
  3386. const schemaSchema = optionObjOf(name, [optionOf('config', modes)]);
  3387. return doCreate(configSchema, schemaSchema, name, active, apis, extra, state);
  3388. };
  3389. const wrapApi = (bName, apiFunction, apiName) => {
  3390. const f = (component, ...rest) => {
  3391. const args = [component].concat(rest);
  3392. return component.config({ name: constant$1(bName) }).fold(() => {
  3393. throw new Error('We could not find any behaviour configuration for: ' + bName + '. Using API: ' + apiName);
  3394. }, info => {
  3395. const rest = Array.prototype.slice.call(args, 1);
  3396. return apiFunction.apply(undefined, [
  3397. component,
  3398. info.config,
  3399. info.state
  3400. ].concat(rest));
  3401. });
  3402. };
  3403. return markAsBehaviourApi(f, apiName, apiFunction);
  3404. };
  3405. const revokeBehaviour = name => ({
  3406. key: name,
  3407. value: undefined
  3408. });
  3409. const doCreate = (configSchema, schemaSchema, name, active, apis, extra, state) => {
  3410. const getConfig = info => hasNonNullableKey(info, name) ? info[name]() : Optional.none();
  3411. const wrappedApis = map$1(apis, (apiF, apiName) => wrapApi(name, apiF, apiName));
  3412. const wrappedExtra = map$1(extra, (extraF, extraName) => markAsExtraApi(extraF, extraName));
  3413. const me = {
  3414. ...wrappedExtra,
  3415. ...wrappedApis,
  3416. revoke: curry(revokeBehaviour, name),
  3417. config: spec => {
  3418. const prepared = asRawOrDie$1(name + '-config', configSchema, spec);
  3419. return {
  3420. key: name,
  3421. value: {
  3422. config: prepared,
  3423. me,
  3424. configAsRaw: cached(() => asRawOrDie$1(name + '-config', configSchema, spec)),
  3425. initialConfig: spec,
  3426. state
  3427. }
  3428. };
  3429. },
  3430. schema: constant$1(schemaSchema),
  3431. exhibit: (info, base) => {
  3432. return lift2(getConfig(info), get$g(active, 'exhibit'), (behaviourInfo, exhibitor) => {
  3433. return exhibitor(base, behaviourInfo.config, behaviourInfo.state);
  3434. }).getOrThunk(() => nu$7({}));
  3435. },
  3436. name: constant$1(name),
  3437. handlers: info => {
  3438. return getConfig(info).map(behaviourInfo => {
  3439. const getEvents = get$g(active, 'events').getOr(() => ({}));
  3440. return getEvents(behaviourInfo.config, behaviourInfo.state);
  3441. }).getOr({});
  3442. }
  3443. };
  3444. return me;
  3445. };
  3446. const derive$1 = capabilities => wrapAll(capabilities);
  3447. const simpleSchema = objOfOnly([
  3448. required$1('fields'),
  3449. required$1('name'),
  3450. defaulted('active', {}),
  3451. defaulted('apis', {}),
  3452. defaulted('state', NoState),
  3453. defaulted('extra', {})
  3454. ]);
  3455. const create$3 = data => {
  3456. const value = asRawOrDie$1('Creating behaviour: ' + data.name, simpleSchema, data);
  3457. return create$4(value.fields, value.name, value.active, value.apis, value.extra, value.state);
  3458. };
  3459. const modeSchema = objOfOnly([
  3460. required$1('branchKey'),
  3461. required$1('branches'),
  3462. required$1('name'),
  3463. defaulted('active', {}),
  3464. defaulted('apis', {}),
  3465. defaulted('state', NoState),
  3466. defaulted('extra', {})
  3467. ]);
  3468. const createModes = data => {
  3469. const value = asRawOrDie$1('Creating behaviour: ' + data.name, modeSchema, data);
  3470. return createModes$1(choose$1(value.branchKey, value.branches), value.name, value.active, value.apis, value.extra, value.state);
  3471. };
  3472. const revoke = constant$1(undefined);
  3473. const Receiving = create$3({
  3474. fields: ReceivingSchema,
  3475. name: 'receiving',
  3476. active: ActiveReceiving
  3477. });
  3478. const exhibit$6 = (base, posConfig) => nu$7({
  3479. classes: [],
  3480. styles: posConfig.useFixed() ? {} : { position: 'relative' }
  3481. });
  3482. var ActivePosition = /*#__PURE__*/Object.freeze({
  3483. __proto__: null,
  3484. exhibit: exhibit$6
  3485. });
  3486. const focus$3 = element => element.dom.focus();
  3487. const blur$1 = element => element.dom.blur();
  3488. const hasFocus = element => {
  3489. const root = getRootNode(element).dom;
  3490. return element.dom === root.activeElement;
  3491. };
  3492. const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
  3493. const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
  3494. const preserve$1 = (f, container) => {
  3495. const dos = getRootNode(container);
  3496. const refocus = active$1(dos).bind(focused => {
  3497. const hasFocus = elem => eq(focused, elem);
  3498. return hasFocus(container) ? Optional.some(container) : descendant$1(container, hasFocus);
  3499. });
  3500. const result = f(container);
  3501. refocus.each(oldFocus => {
  3502. active$1(dos).filter(newFocus => eq(newFocus, oldFocus)).fold(() => {
  3503. focus$3(oldFocus);
  3504. }, noop);
  3505. });
  3506. return result;
  3507. };
  3508. const NuPositionCss = (position, left, top, right, bottom) => {
  3509. const toPx = num => num + 'px';
  3510. return {
  3511. position,
  3512. left: left.map(toPx),
  3513. top: top.map(toPx),
  3514. right: right.map(toPx),
  3515. bottom: bottom.map(toPx)
  3516. };
  3517. };
  3518. const toOptions = position => ({
  3519. ...position,
  3520. position: Optional.some(position.position)
  3521. });
  3522. const applyPositionCss = (element, position) => {
  3523. setOptions(element, toOptions(position));
  3524. };
  3525. const adt$9 = Adt.generate([
  3526. { none: [] },
  3527. {
  3528. relative: [
  3529. 'x',
  3530. 'y',
  3531. 'width',
  3532. 'height'
  3533. ]
  3534. },
  3535. {
  3536. fixed: [
  3537. 'x',
  3538. 'y',
  3539. 'width',
  3540. 'height'
  3541. ]
  3542. }
  3543. ]);
  3544. const positionWithDirection = (posName, decision, x, y, width, height) => {
  3545. const decisionRect = decision.rect;
  3546. const decisionX = decisionRect.x - x;
  3547. const decisionY = decisionRect.y - y;
  3548. const decisionWidth = decisionRect.width;
  3549. const decisionHeight = decisionRect.height;
  3550. const decisionRight = width - (decisionX + decisionWidth);
  3551. const decisionBottom = height - (decisionY + decisionHeight);
  3552. const left = Optional.some(decisionX);
  3553. const top = Optional.some(decisionY);
  3554. const right = Optional.some(decisionRight);
  3555. const bottom = Optional.some(decisionBottom);
  3556. const none = Optional.none();
  3557. 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));
  3558. };
  3559. const reposition = (origin, decision) => origin.fold(() => {
  3560. const decisionRect = decision.rect;
  3561. return NuPositionCss('absolute', Optional.some(decisionRect.x), Optional.some(decisionRect.y), Optional.none(), Optional.none());
  3562. }, (x, y, width, height) => {
  3563. return positionWithDirection('absolute', decision, x, y, width, height);
  3564. }, (x, y, width, height) => {
  3565. return positionWithDirection('fixed', decision, x, y, width, height);
  3566. });
  3567. const toBox = (origin, element) => {
  3568. const rel = curry(find$2, element);
  3569. const position = origin.fold(rel, rel, () => {
  3570. const scroll = get$b();
  3571. return find$2(element).translate(-scroll.left, -scroll.top);
  3572. });
  3573. const width = getOuter$1(element);
  3574. const height = getOuter$2(element);
  3575. return bounds(position.left, position.top, width, height);
  3576. };
  3577. const viewport = (origin, getBounds) => getBounds.fold(() => origin.fold(win, win, bounds), b => origin.fold(b, b, () => {
  3578. const bounds$1 = b();
  3579. const pos = translate$2(origin, bounds$1.x, bounds$1.y);
  3580. return bounds(pos.left, pos.top, bounds$1.width, bounds$1.height);
  3581. }));
  3582. const translate$2 = (origin, x, y) => {
  3583. const pos = SugarPosition(x, y);
  3584. const removeScroll = () => {
  3585. const outerScroll = get$b();
  3586. return pos.translate(-outerScroll.left, -outerScroll.top);
  3587. };
  3588. return origin.fold(constant$1(pos), constant$1(pos), removeScroll);
  3589. };
  3590. const cata$1 = (subject, onNone, onRelative, onFixed) => subject.fold(onNone, onRelative, onFixed);
  3591. adt$9.none;
  3592. const relative$1 = adt$9.relative;
  3593. const fixed$1 = adt$9.fixed;
  3594. const anchor = (anchorBox, origin) => ({
  3595. anchorBox,
  3596. origin
  3597. });
  3598. const box = (anchorBox, origin) => anchor(anchorBox, origin);
  3599. const placementAttribute = 'data-alloy-placement';
  3600. const setPlacement$1 = (element, placement) => {
  3601. set$9(element, placementAttribute, placement);
  3602. };
  3603. const getPlacement = element => getOpt(element, placementAttribute);
  3604. const reset$2 = element => remove$7(element, placementAttribute);
  3605. const adt$8 = Adt.generate([
  3606. { fit: ['reposition'] },
  3607. {
  3608. nofit: [
  3609. 'reposition',
  3610. 'visibleW',
  3611. 'visibleH',
  3612. 'isVisible'
  3613. ]
  3614. }
  3615. ]);
  3616. const determinePosition = (box, bounds) => {
  3617. const {
  3618. x: boundsX,
  3619. y: boundsY,
  3620. right: boundsRight,
  3621. bottom: boundsBottom
  3622. } = bounds;
  3623. const {x, y, right, bottom, width, height} = box;
  3624. const xInBounds = x >= boundsX && x <= boundsRight;
  3625. const yInBounds = y >= boundsY && y <= boundsBottom;
  3626. const originInBounds = xInBounds && yInBounds;
  3627. const rightInBounds = right <= boundsRight && right >= boundsX;
  3628. const bottomInBounds = bottom <= boundsBottom && bottom >= boundsY;
  3629. const sizeInBounds = rightInBounds && bottomInBounds;
  3630. const visibleW = Math.min(width, x >= boundsX ? boundsRight - x : right - boundsX);
  3631. const visibleH = Math.min(height, y >= boundsY ? boundsBottom - y : bottom - boundsY);
  3632. return {
  3633. originInBounds,
  3634. sizeInBounds,
  3635. visibleW,
  3636. visibleH
  3637. };
  3638. };
  3639. const calcReposition = (box, bounds$1) => {
  3640. const {
  3641. x: boundsX,
  3642. y: boundsY,
  3643. right: boundsRight,
  3644. bottom: boundsBottom
  3645. } = bounds$1;
  3646. const {x, y, width, height} = box;
  3647. const maxX = Math.max(boundsX, boundsRight - width);
  3648. const maxY = Math.max(boundsY, boundsBottom - height);
  3649. const restrictedX = clamp(x, boundsX, maxX);
  3650. const restrictedY = clamp(y, boundsY, maxY);
  3651. const restrictedWidth = Math.min(restrictedX + width, boundsRight) - restrictedX;
  3652. const restrictedHeight = Math.min(restrictedY + height, boundsBottom) - restrictedY;
  3653. return bounds(restrictedX, restrictedY, restrictedWidth, restrictedHeight);
  3654. };
  3655. const calcMaxSizes = (direction, box, bounds) => {
  3656. const upAvailable = constant$1(box.bottom - bounds.y);
  3657. const downAvailable = constant$1(bounds.bottom - box.y);
  3658. const maxHeight = cataVertical(direction, downAvailable, downAvailable, upAvailable);
  3659. const westAvailable = constant$1(box.right - bounds.x);
  3660. const eastAvailable = constant$1(bounds.right - box.x);
  3661. const maxWidth = cataHorizontal(direction, eastAvailable, eastAvailable, westAvailable);
  3662. return {
  3663. maxWidth,
  3664. maxHeight
  3665. };
  3666. };
  3667. const attempt = (candidate, width, height, bounds$1) => {
  3668. const bubble = candidate.bubble;
  3669. const bubbleOffset = bubble.offset;
  3670. const adjustedBounds = adjustBounds(bounds$1, candidate.restriction, bubbleOffset);
  3671. const newX = candidate.x + bubbleOffset.left;
  3672. const newY = candidate.y + bubbleOffset.top;
  3673. const box = bounds(newX, newY, width, height);
  3674. const {originInBounds, sizeInBounds, visibleW, visibleH} = determinePosition(box, adjustedBounds);
  3675. const fits = originInBounds && sizeInBounds;
  3676. const fittedBox = fits ? box : calcReposition(box, adjustedBounds);
  3677. const isPartlyVisible = fittedBox.width > 0 && fittedBox.height > 0;
  3678. const {maxWidth, maxHeight} = calcMaxSizes(candidate.direction, fittedBox, bounds$1);
  3679. const reposition = {
  3680. rect: fittedBox,
  3681. maxHeight,
  3682. maxWidth,
  3683. direction: candidate.direction,
  3684. placement: candidate.placement,
  3685. classes: {
  3686. on: bubble.classesOn,
  3687. off: bubble.classesOff
  3688. },
  3689. layout: candidate.label,
  3690. testY: newY
  3691. };
  3692. return fits || candidate.alwaysFit ? adt$8.fit(reposition) : adt$8.nofit(reposition, visibleW, visibleH, isPartlyVisible);
  3693. };
  3694. const attempts = (element, candidates, anchorBox, elementBox, bubbles, bounds) => {
  3695. const panelWidth = elementBox.width;
  3696. const panelHeight = elementBox.height;
  3697. const attemptBestFit = (layout, reposition, visibleW, visibleH, isVisible) => {
  3698. const next = layout(anchorBox, elementBox, bubbles, element, bounds);
  3699. const attemptLayout = attempt(next, panelWidth, panelHeight, bounds);
  3700. return attemptLayout.fold(constant$1(attemptLayout), (newReposition, newVisibleW, newVisibleH, newIsVisible) => {
  3701. const improved = isVisible === newIsVisible ? newVisibleH > visibleH || newVisibleW > visibleW : !isVisible && newIsVisible;
  3702. return improved ? attemptLayout : adt$8.nofit(reposition, visibleW, visibleH, isVisible);
  3703. });
  3704. };
  3705. const abc = foldl(candidates, (b, a) => {
  3706. const bestNext = curry(attemptBestFit, a);
  3707. return b.fold(constant$1(b), bestNext);
  3708. }, adt$8.nofit({
  3709. rect: anchorBox,
  3710. maxHeight: elementBox.height,
  3711. maxWidth: elementBox.width,
  3712. direction: southeast$3(),
  3713. placement: 'southeast',
  3714. classes: {
  3715. on: [],
  3716. off: []
  3717. },
  3718. layout: 'none',
  3719. testY: anchorBox.y
  3720. }, -1, -1, false));
  3721. return abc.fold(identity, identity);
  3722. };
  3723. const singleton = doRevoke => {
  3724. const subject = Cell(Optional.none());
  3725. const revoke = () => subject.get().each(doRevoke);
  3726. const clear = () => {
  3727. revoke();
  3728. subject.set(Optional.none());
  3729. };
  3730. const isSet = () => subject.get().isSome();
  3731. const get = () => subject.get();
  3732. const set = s => {
  3733. revoke();
  3734. subject.set(Optional.some(s));
  3735. };
  3736. return {
  3737. clear,
  3738. isSet,
  3739. get,
  3740. set
  3741. };
  3742. };
  3743. const destroyable = () => singleton(s => s.destroy());
  3744. const unbindable = () => singleton(s => s.unbind());
  3745. const value$2 = () => {
  3746. const subject = singleton(noop);
  3747. const on = f => subject.get().each(f);
  3748. return {
  3749. ...subject,
  3750. on
  3751. };
  3752. };
  3753. const filter = always;
  3754. const bind = (element, event, handler) => bind$2(element, event, filter, handler);
  3755. const capture = (element, event, handler) => capture$1(element, event, filter, handler);
  3756. const fromRawEvent = fromRawEvent$1;
  3757. const properties = [
  3758. 'top',
  3759. 'bottom',
  3760. 'right',
  3761. 'left'
  3762. ];
  3763. const timerAttr = 'data-alloy-transition-timer';
  3764. const isTransitioning$1 = (element, transition) => hasAll(element, transition.classes);
  3765. const shouldApplyTransitionCss = (transition, decision, lastPlacement) => {
  3766. return lastPlacement.exists(placer => {
  3767. const mode = transition.mode;
  3768. return mode === 'all' ? true : placer[mode] !== decision[mode];
  3769. });
  3770. };
  3771. const hasChanges = (position, intermediate) => {
  3772. const round = value => parseFloat(value).toFixed(3);
  3773. return find$4(intermediate, (value, key) => {
  3774. const newValue = position[key].map(round);
  3775. const val = value.map(round);
  3776. return !equals(newValue, val);
  3777. }).isSome();
  3778. };
  3779. const getTransitionDuration = element => {
  3780. const get = name => {
  3781. const style = get$e(element, name);
  3782. const times = style.split(/\s*,\s*/);
  3783. return filter$2(times, isNotEmpty);
  3784. };
  3785. const parse = value => {
  3786. if (isString(value) && /^[\d.]+/.test(value)) {
  3787. const num = parseFloat(value);
  3788. return endsWith(value, 'ms') ? num : num * 1000;
  3789. } else {
  3790. return 0;
  3791. }
  3792. };
  3793. const delay = get('transition-delay');
  3794. const duration = get('transition-duration');
  3795. return foldl(duration, (acc, dur, i) => {
  3796. const time = parse(delay[i]) + parse(dur);
  3797. return Math.max(acc, time);
  3798. }, 0);
  3799. };
  3800. const setupTransitionListeners = (element, transition) => {
  3801. const transitionEnd = unbindable();
  3802. const transitionCancel = unbindable();
  3803. let timer;
  3804. const isSourceTransition = e => {
  3805. var _a;
  3806. const pseudoElement = (_a = e.raw.pseudoElement) !== null && _a !== void 0 ? _a : '';
  3807. return eq(e.target, element) && isEmpty(pseudoElement) && contains$2(properties, e.raw.propertyName);
  3808. };
  3809. const transitionDone = e => {
  3810. if (isNullable(e) || isSourceTransition(e)) {
  3811. transitionEnd.clear();
  3812. transitionCancel.clear();
  3813. const type = e === null || e === void 0 ? void 0 : e.raw.type;
  3814. if (isNullable(type) || type === transitionend()) {
  3815. clearTimeout(timer);
  3816. remove$7(element, timerAttr);
  3817. remove$1(element, transition.classes);
  3818. }
  3819. }
  3820. };
  3821. const transitionStart = bind(element, transitionstart(), e => {
  3822. if (isSourceTransition(e)) {
  3823. transitionStart.unbind();
  3824. transitionEnd.set(bind(element, transitionend(), transitionDone));
  3825. transitionCancel.set(bind(element, transitioncancel(), transitionDone));
  3826. }
  3827. });
  3828. const duration = getTransitionDuration(element);
  3829. requestAnimationFrame(() => {
  3830. timer = setTimeout(transitionDone, duration + 17);
  3831. set$9(element, timerAttr, timer);
  3832. });
  3833. };
  3834. const startTransitioning = (element, transition) => {
  3835. add$1(element, transition.classes);
  3836. getOpt(element, timerAttr).each(timerId => {
  3837. clearTimeout(parseInt(timerId, 10));
  3838. remove$7(element, timerAttr);
  3839. });
  3840. setupTransitionListeners(element, transition);
  3841. };
  3842. const applyTransitionCss = (element, origin, position, transition, decision, lastPlacement) => {
  3843. const shouldTransition = shouldApplyTransitionCss(transition, decision, lastPlacement);
  3844. if (shouldTransition || isTransitioning$1(element, transition)) {
  3845. set$8(element, 'position', position.position);
  3846. const rect = toBox(origin, element);
  3847. const intermediatePosition = reposition(origin, {
  3848. ...decision,
  3849. rect
  3850. });
  3851. const intermediateCssOptions = mapToObject(properties, prop => intermediatePosition[prop]);
  3852. if (hasChanges(position, intermediateCssOptions)) {
  3853. setOptions(element, intermediateCssOptions);
  3854. if (shouldTransition) {
  3855. startTransitioning(element, transition);
  3856. }
  3857. reflow(element);
  3858. }
  3859. } else {
  3860. remove$1(element, transition.classes);
  3861. }
  3862. };
  3863. const elementSize = p => ({
  3864. width: getOuter$1(p),
  3865. height: getOuter$2(p)
  3866. });
  3867. const layout = (anchorBox, element, bubbles, options) => {
  3868. remove$6(element, 'max-height');
  3869. remove$6(element, 'max-width');
  3870. const elementBox = elementSize(element);
  3871. return attempts(element, options.preference, anchorBox, elementBox, bubbles, options.bounds);
  3872. };
  3873. const setClasses = (element, decision) => {
  3874. const classInfo = decision.classes;
  3875. remove$1(element, classInfo.off);
  3876. add$1(element, classInfo.on);
  3877. };
  3878. const setHeight = (element, decision, options) => {
  3879. const maxHeightFunction = options.maxHeightFunction;
  3880. maxHeightFunction(element, decision.maxHeight);
  3881. };
  3882. const setWidth = (element, decision, options) => {
  3883. const maxWidthFunction = options.maxWidthFunction;
  3884. maxWidthFunction(element, decision.maxWidth);
  3885. };
  3886. const position$2 = (element, decision, options) => {
  3887. const positionCss = reposition(options.origin, decision);
  3888. options.transition.each(transition => {
  3889. applyTransitionCss(element, options.origin, positionCss, transition, decision, options.lastPlacement);
  3890. });
  3891. applyPositionCss(element, positionCss);
  3892. };
  3893. const setPlacement = (element, decision) => {
  3894. setPlacement$1(element, decision.placement);
  3895. };
  3896. const setMaxHeight = (element, maxHeight) => {
  3897. setMax$1(element, Math.floor(maxHeight));
  3898. };
  3899. const anchored = constant$1((element, available) => {
  3900. setMaxHeight(element, available);
  3901. setAll(element, {
  3902. 'overflow-x': 'hidden',
  3903. 'overflow-y': 'auto'
  3904. });
  3905. });
  3906. const expandable$1 = constant$1((element, available) => {
  3907. setMaxHeight(element, available);
  3908. });
  3909. const defaultOr = (options, key, dephault) => options[key] === undefined ? dephault : options[key];
  3910. const simple = (anchor, element, bubble, layouts, lastPlacement, getBounds, overrideOptions, transition) => {
  3911. const maxHeightFunction = defaultOr(overrideOptions, 'maxHeightFunction', anchored());
  3912. const maxWidthFunction = defaultOr(overrideOptions, 'maxWidthFunction', noop);
  3913. const anchorBox = anchor.anchorBox;
  3914. const origin = anchor.origin;
  3915. const options = {
  3916. bounds: viewport(origin, getBounds),
  3917. origin,
  3918. preference: layouts,
  3919. maxHeightFunction,
  3920. maxWidthFunction,
  3921. lastPlacement,
  3922. transition
  3923. };
  3924. return go(anchorBox, element, bubble, options);
  3925. };
  3926. const go = (anchorBox, element, bubble, options) => {
  3927. const decision = layout(anchorBox, element, bubble, options);
  3928. position$2(element, decision, options);
  3929. setPlacement(element, decision);
  3930. setClasses(element, decision);
  3931. setHeight(element, decision, options);
  3932. setWidth(element, decision, options);
  3933. return {
  3934. layout: decision.layout,
  3935. placement: decision.placement
  3936. };
  3937. };
  3938. const allAlignments = [
  3939. 'valignCentre',
  3940. 'alignLeft',
  3941. 'alignRight',
  3942. 'alignCentre',
  3943. 'top',
  3944. 'bottom',
  3945. 'left',
  3946. 'right',
  3947. 'inset'
  3948. ];
  3949. const nu$5 = (xOffset, yOffset, classes, insetModifier = 1) => {
  3950. const insetXOffset = xOffset * insetModifier;
  3951. const insetYOffset = yOffset * insetModifier;
  3952. const getClasses = prop => get$g(classes, prop).getOr([]);
  3953. const make = (xDelta, yDelta, alignmentsOn) => {
  3954. const alignmentsOff = difference(allAlignments, alignmentsOn);
  3955. return {
  3956. offset: SugarPosition(xDelta, yDelta),
  3957. classesOn: bind$3(alignmentsOn, getClasses),
  3958. classesOff: bind$3(alignmentsOff, getClasses)
  3959. };
  3960. };
  3961. return {
  3962. southeast: () => make(-xOffset, yOffset, [
  3963. 'top',
  3964. 'alignLeft'
  3965. ]),
  3966. southwest: () => make(xOffset, yOffset, [
  3967. 'top',
  3968. 'alignRight'
  3969. ]),
  3970. south: () => make(-xOffset / 2, yOffset, [
  3971. 'top',
  3972. 'alignCentre'
  3973. ]),
  3974. northeast: () => make(-xOffset, -yOffset, [
  3975. 'bottom',
  3976. 'alignLeft'
  3977. ]),
  3978. northwest: () => make(xOffset, -yOffset, [
  3979. 'bottom',
  3980. 'alignRight'
  3981. ]),
  3982. north: () => make(-xOffset / 2, -yOffset, [
  3983. 'bottom',
  3984. 'alignCentre'
  3985. ]),
  3986. east: () => make(xOffset, -yOffset / 2, [
  3987. 'valignCentre',
  3988. 'left'
  3989. ]),
  3990. west: () => make(-xOffset, -yOffset / 2, [
  3991. 'valignCentre',
  3992. 'right'
  3993. ]),
  3994. insetNortheast: () => make(insetXOffset, insetYOffset, [
  3995. 'top',
  3996. 'alignLeft',
  3997. 'inset'
  3998. ]),
  3999. insetNorthwest: () => make(-insetXOffset, insetYOffset, [
  4000. 'top',
  4001. 'alignRight',
  4002. 'inset'
  4003. ]),
  4004. insetNorth: () => make(-insetXOffset / 2, insetYOffset, [
  4005. 'top',
  4006. 'alignCentre',
  4007. 'inset'
  4008. ]),
  4009. insetSoutheast: () => make(insetXOffset, -insetYOffset, [
  4010. 'bottom',
  4011. 'alignLeft',
  4012. 'inset'
  4013. ]),
  4014. insetSouthwest: () => make(-insetXOffset, -insetYOffset, [
  4015. 'bottom',
  4016. 'alignRight',
  4017. 'inset'
  4018. ]),
  4019. insetSouth: () => make(-insetXOffset / 2, -insetYOffset, [
  4020. 'bottom',
  4021. 'alignCentre',
  4022. 'inset'
  4023. ]),
  4024. insetEast: () => make(-insetXOffset, -insetYOffset / 2, [
  4025. 'valignCentre',
  4026. 'right',
  4027. 'inset'
  4028. ]),
  4029. insetWest: () => make(insetXOffset, -insetYOffset / 2, [
  4030. 'valignCentre',
  4031. 'left',
  4032. 'inset'
  4033. ])
  4034. };
  4035. };
  4036. const fallback = () => nu$5(0, 0, {});
  4037. const nu$4 = identity;
  4038. const onDirection = (isLtr, isRtl) => element => getDirection(element) === 'rtl' ? isRtl : isLtr;
  4039. const getDirection = element => get$e(element, 'direction') === 'rtl' ? 'rtl' : 'ltr';
  4040. var AttributeValue;
  4041. (function (AttributeValue) {
  4042. AttributeValue['TopToBottom'] = 'toptobottom';
  4043. AttributeValue['BottomToTop'] = 'bottomtotop';
  4044. }(AttributeValue || (AttributeValue = {})));
  4045. const Attribute = 'data-alloy-vertical-dir';
  4046. const isBottomToTopDir = el => closest$2(el, current => isElement$1(current) && get$f(current, 'data-alloy-vertical-dir') === AttributeValue.BottomToTop);
  4047. const schema$y = () => optionObjOf('layouts', [
  4048. required$1('onLtr'),
  4049. required$1('onRtl'),
  4050. option$3('onBottomLtr'),
  4051. option$3('onBottomRtl')
  4052. ]);
  4053. const get$5 = (elem, info, defaultLtr, defaultRtl, defaultBottomLtr, defaultBottomRtl, dirElement) => {
  4054. const isBottomToTop = dirElement.map(isBottomToTopDir).getOr(false);
  4055. const customLtr = info.layouts.map(ls => ls.onLtr(elem));
  4056. const customRtl = info.layouts.map(ls => ls.onRtl(elem));
  4057. const ltr = isBottomToTop ? info.layouts.bind(ls => ls.onBottomLtr.map(f => f(elem))).or(customLtr).getOr(defaultBottomLtr) : customLtr.getOr(defaultLtr);
  4058. const rtl = isBottomToTop ? info.layouts.bind(ls => ls.onBottomRtl.map(f => f(elem))).or(customRtl).getOr(defaultBottomRtl) : customRtl.getOr(defaultRtl);
  4059. const f = onDirection(ltr, rtl);
  4060. return f(elem);
  4061. };
  4062. const placement$4 = (component, anchorInfo, origin) => {
  4063. const hotspot = anchorInfo.hotspot;
  4064. const anchorBox = toBox(origin, hotspot.element);
  4065. const layouts = get$5(component.element, anchorInfo, belowOrAbove(), belowOrAboveRtl(), aboveOrBelow(), aboveOrBelowRtl(), Optional.some(anchorInfo.hotspot.element));
  4066. return Optional.some(nu$4({
  4067. anchorBox,
  4068. bubble: anchorInfo.bubble.getOr(fallback()),
  4069. overrides: anchorInfo.overrides,
  4070. layouts,
  4071. placer: Optional.none()
  4072. }));
  4073. };
  4074. var HotspotAnchor = [
  4075. required$1('hotspot'),
  4076. option$3('bubble'),
  4077. defaulted('overrides', {}),
  4078. schema$y(),
  4079. output$1('placement', placement$4)
  4080. ];
  4081. const placement$3 = (component, anchorInfo, origin) => {
  4082. const pos = translate$2(origin, anchorInfo.x, anchorInfo.y);
  4083. const anchorBox = bounds(pos.left, pos.top, anchorInfo.width, anchorInfo.height);
  4084. const layouts = get$5(component.element, anchorInfo, all$1(), allRtl$1(), all$1(), allRtl$1(), Optional.none());
  4085. return Optional.some(nu$4({
  4086. anchorBox,
  4087. bubble: anchorInfo.bubble,
  4088. overrides: anchorInfo.overrides,
  4089. layouts,
  4090. placer: Optional.none()
  4091. }));
  4092. };
  4093. var MakeshiftAnchor = [
  4094. required$1('x'),
  4095. required$1('y'),
  4096. defaulted('height', 0),
  4097. defaulted('width', 0),
  4098. defaulted('bubble', fallback()),
  4099. defaulted('overrides', {}),
  4100. schema$y(),
  4101. output$1('placement', placement$3)
  4102. ];
  4103. const adt$7 = Adt.generate([
  4104. { screen: ['point'] },
  4105. {
  4106. absolute: [
  4107. 'point',
  4108. 'scrollLeft',
  4109. 'scrollTop'
  4110. ]
  4111. }
  4112. ]);
  4113. const toFixed = pos => pos.fold(identity, (point, scrollLeft, scrollTop) => point.translate(-scrollLeft, -scrollTop));
  4114. const toAbsolute = pos => pos.fold(identity, identity);
  4115. const sum = points => foldl(points, (b, a) => b.translate(a.left, a.top), SugarPosition(0, 0));
  4116. const sumAsFixed = positions => {
  4117. const points = map$2(positions, toFixed);
  4118. return sum(points);
  4119. };
  4120. const sumAsAbsolute = positions => {
  4121. const points = map$2(positions, toAbsolute);
  4122. return sum(points);
  4123. };
  4124. const screen = adt$7.screen;
  4125. const absolute$1 = adt$7.absolute;
  4126. const getOffset = (component, origin, anchorInfo) => {
  4127. const win = defaultView(anchorInfo.root).dom;
  4128. const hasSameOwner = frame => {
  4129. const frameOwner = owner$4(frame);
  4130. const compOwner = owner$4(component.element);
  4131. return eq(frameOwner, compOwner);
  4132. };
  4133. return Optional.from(win.frameElement).map(SugarElement.fromDom).filter(hasSameOwner).map(absolute$3);
  4134. };
  4135. const getRootPoint = (component, origin, anchorInfo) => {
  4136. const doc = owner$4(component.element);
  4137. const outerScroll = get$b(doc);
  4138. const offset = getOffset(component, origin, anchorInfo).getOr(outerScroll);
  4139. return absolute$1(offset, outerScroll.left, outerScroll.top);
  4140. };
  4141. const getBox = (left, top, width, height) => {
  4142. const point = screen(SugarPosition(left, top));
  4143. return Optional.some(pointed(point, width, height));
  4144. };
  4145. const calcNewAnchor = (optBox, rootPoint, anchorInfo, origin, elem) => optBox.map(box => {
  4146. const points = [
  4147. rootPoint,
  4148. box.point
  4149. ];
  4150. const topLeft = cata$1(origin, () => sumAsAbsolute(points), () => sumAsAbsolute(points), () => sumAsFixed(points));
  4151. const anchorBox = rect(topLeft.left, topLeft.top, box.width, box.height);
  4152. const layoutsLtr = anchorInfo.showAbove ? aboveOrBelow() : belowOrAbove();
  4153. const layoutsRtl = anchorInfo.showAbove ? aboveOrBelowRtl() : belowOrAboveRtl();
  4154. const layouts = get$5(elem, anchorInfo, layoutsLtr, layoutsRtl, layoutsLtr, layoutsRtl, Optional.none());
  4155. return nu$4({
  4156. anchorBox,
  4157. bubble: anchorInfo.bubble.getOr(fallback()),
  4158. overrides: anchorInfo.overrides,
  4159. layouts,
  4160. placer: Optional.none()
  4161. });
  4162. });
  4163. const placement$2 = (component, anchorInfo, origin) => {
  4164. const rootPoint = getRootPoint(component, origin, anchorInfo);
  4165. return anchorInfo.node.filter(inBody).bind(target => {
  4166. const rect = target.dom.getBoundingClientRect();
  4167. const nodeBox = getBox(rect.left, rect.top, rect.width, rect.height);
  4168. const elem = anchorInfo.node.getOr(component.element);
  4169. return calcNewAnchor(nodeBox, rootPoint, anchorInfo, origin, elem);
  4170. });
  4171. };
  4172. var NodeAnchor = [
  4173. required$1('node'),
  4174. required$1('root'),
  4175. option$3('bubble'),
  4176. schema$y(),
  4177. defaulted('overrides', {}),
  4178. defaulted('showAbove', false),
  4179. output$1('placement', placement$2)
  4180. ];
  4181. const zeroWidth = '\uFEFF';
  4182. const nbsp = '\xA0';
  4183. const create$2 = (start, soffset, finish, foffset) => ({
  4184. start,
  4185. soffset,
  4186. finish,
  4187. foffset
  4188. });
  4189. const SimRange = { create: create$2 };
  4190. const adt$6 = Adt.generate([
  4191. { before: ['element'] },
  4192. {
  4193. on: [
  4194. 'element',
  4195. 'offset'
  4196. ]
  4197. },
  4198. { after: ['element'] }
  4199. ]);
  4200. const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
  4201. const getStart$1 = situ => situ.fold(identity, identity, identity);
  4202. const before = adt$6.before;
  4203. const on$1 = adt$6.on;
  4204. const after$1 = adt$6.after;
  4205. const Situ = {
  4206. before,
  4207. on: on$1,
  4208. after: after$1,
  4209. cata,
  4210. getStart: getStart$1
  4211. };
  4212. const adt$5 = Adt.generate([
  4213. { domRange: ['rng'] },
  4214. {
  4215. relative: [
  4216. 'startSitu',
  4217. 'finishSitu'
  4218. ]
  4219. },
  4220. {
  4221. exact: [
  4222. 'start',
  4223. 'soffset',
  4224. 'finish',
  4225. 'foffset'
  4226. ]
  4227. }
  4228. ]);
  4229. const exactFromRange = simRange => adt$5.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
  4230. const getStart = selection => selection.match({
  4231. domRange: rng => SugarElement.fromDom(rng.startContainer),
  4232. relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
  4233. exact: (start, _soffset, _finish, _foffset) => start
  4234. });
  4235. const domRange = adt$5.domRange;
  4236. const relative = adt$5.relative;
  4237. const exact = adt$5.exact;
  4238. const getWin = selection => {
  4239. const start = getStart(selection);
  4240. return defaultView(start);
  4241. };
  4242. const range$1 = SimRange.create;
  4243. const SimSelection = {
  4244. domRange,
  4245. relative,
  4246. exact,
  4247. exactFromRange,
  4248. getWin,
  4249. range: range$1
  4250. };
  4251. const setStart = (rng, situ) => {
  4252. situ.fold(e => {
  4253. rng.setStartBefore(e.dom);
  4254. }, (e, o) => {
  4255. rng.setStart(e.dom, o);
  4256. }, e => {
  4257. rng.setStartAfter(e.dom);
  4258. });
  4259. };
  4260. const setFinish = (rng, situ) => {
  4261. situ.fold(e => {
  4262. rng.setEndBefore(e.dom);
  4263. }, (e, o) => {
  4264. rng.setEnd(e.dom, o);
  4265. }, e => {
  4266. rng.setEndAfter(e.dom);
  4267. });
  4268. };
  4269. const relativeToNative = (win, startSitu, finishSitu) => {
  4270. const range = win.document.createRange();
  4271. setStart(range, startSitu);
  4272. setFinish(range, finishSitu);
  4273. return range;
  4274. };
  4275. const exactToNative = (win, start, soffset, finish, foffset) => {
  4276. const rng = win.document.createRange();
  4277. rng.setStart(start.dom, soffset);
  4278. rng.setEnd(finish.dom, foffset);
  4279. return rng;
  4280. };
  4281. const toRect = rect => ({
  4282. left: rect.left,
  4283. top: rect.top,
  4284. right: rect.right,
  4285. bottom: rect.bottom,
  4286. width: rect.width,
  4287. height: rect.height
  4288. });
  4289. const getFirstRect$1 = rng => {
  4290. const rects = rng.getClientRects();
  4291. const rect = rects.length > 0 ? rects[0] : rng.getBoundingClientRect();
  4292. return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
  4293. };
  4294. const getBounds$2 = rng => {
  4295. const rect = rng.getBoundingClientRect();
  4296. return rect.width > 0 || rect.height > 0 ? Optional.some(rect).map(toRect) : Optional.none();
  4297. };
  4298. const adt$4 = Adt.generate([
  4299. {
  4300. ltr: [
  4301. 'start',
  4302. 'soffset',
  4303. 'finish',
  4304. 'foffset'
  4305. ]
  4306. },
  4307. {
  4308. rtl: [
  4309. 'start',
  4310. 'soffset',
  4311. 'finish',
  4312. 'foffset'
  4313. ]
  4314. }
  4315. ]);
  4316. const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
  4317. const getRanges = (win, selection) => selection.match({
  4318. domRange: rng => {
  4319. return {
  4320. ltr: constant$1(rng),
  4321. rtl: Optional.none
  4322. };
  4323. },
  4324. relative: (startSitu, finishSitu) => {
  4325. return {
  4326. ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
  4327. rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
  4328. };
  4329. },
  4330. exact: (start, soffset, finish, foffset) => {
  4331. return {
  4332. ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
  4333. rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
  4334. };
  4335. }
  4336. });
  4337. const doDiagnose = (win, ranges) => {
  4338. const rng = ranges.ltr();
  4339. if (rng.collapsed) {
  4340. const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
  4341. 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));
  4342. } else {
  4343. return fromRange(win, adt$4.ltr, rng);
  4344. }
  4345. };
  4346. const diagnose = (win, selection) => {
  4347. const ranges = getRanges(win, selection);
  4348. return doDiagnose(win, ranges);
  4349. };
  4350. const asLtrRange = (win, selection) => {
  4351. const diagnosis = diagnose(win, selection);
  4352. return diagnosis.match({
  4353. ltr: (start, soffset, finish, foffset) => {
  4354. const rng = win.document.createRange();
  4355. rng.setStart(start.dom, soffset);
  4356. rng.setEnd(finish.dom, foffset);
  4357. return rng;
  4358. },
  4359. rtl: (start, soffset, finish, foffset) => {
  4360. const rng = win.document.createRange();
  4361. rng.setStart(finish.dom, foffset);
  4362. rng.setEnd(start.dom, soffset);
  4363. return rng;
  4364. }
  4365. });
  4366. };
  4367. adt$4.ltr;
  4368. adt$4.rtl;
  4369. const descendants = (scope, selector) => all$3(selector, scope);
  4370. const makeRange = (start, soffset, finish, foffset) => {
  4371. const doc = owner$4(start);
  4372. const rng = doc.dom.createRange();
  4373. rng.setStart(start.dom, soffset);
  4374. rng.setEnd(finish.dom, foffset);
  4375. return rng;
  4376. };
  4377. const after = (start, soffset, finish, foffset) => {
  4378. const r = makeRange(start, soffset, finish, foffset);
  4379. const same = eq(start, finish) && soffset === foffset;
  4380. return r.collapsed && !same;
  4381. };
  4382. const getNativeSelection = win => Optional.from(win.getSelection());
  4383. const readRange = selection => {
  4384. if (selection.rangeCount > 0) {
  4385. const firstRng = selection.getRangeAt(0);
  4386. const lastRng = selection.getRangeAt(selection.rangeCount - 1);
  4387. return Optional.some(SimRange.create(SugarElement.fromDom(firstRng.startContainer), firstRng.startOffset, SugarElement.fromDom(lastRng.endContainer), lastRng.endOffset));
  4388. } else {
  4389. return Optional.none();
  4390. }
  4391. };
  4392. const doGetExact = selection => {
  4393. if (selection.anchorNode === null || selection.focusNode === null) {
  4394. return readRange(selection);
  4395. } else {
  4396. const anchor = SugarElement.fromDom(selection.anchorNode);
  4397. const focus = SugarElement.fromDom(selection.focusNode);
  4398. return after(anchor, selection.anchorOffset, focus, selection.focusOffset) ? Optional.some(SimRange.create(anchor, selection.anchorOffset, focus, selection.focusOffset)) : readRange(selection);
  4399. }
  4400. };
  4401. const getExact = win => getNativeSelection(win).filter(sel => sel.rangeCount > 0).bind(doGetExact);
  4402. const getFirstRect = (win, selection) => {
  4403. const rng = asLtrRange(win, selection);
  4404. return getFirstRect$1(rng);
  4405. };
  4406. const getBounds$1 = (win, selection) => {
  4407. const rng = asLtrRange(win, selection);
  4408. return getBounds$2(rng);
  4409. };
  4410. const NodeValue = (is, name) => {
  4411. const get = element => {
  4412. if (!is(element)) {
  4413. throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
  4414. }
  4415. return getOption(element).getOr('');
  4416. };
  4417. const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
  4418. const set = (element, value) => {
  4419. if (!is(element)) {
  4420. throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
  4421. }
  4422. element.dom.nodeValue = value;
  4423. };
  4424. return {
  4425. get,
  4426. getOption,
  4427. set
  4428. };
  4429. };
  4430. const api = NodeValue(isText, 'text');
  4431. const get$4 = element => api.get(element);
  4432. const point = (element, offset) => ({
  4433. element,
  4434. offset
  4435. });
  4436. const descendOnce$1 = (element, offset) => {
  4437. const children$1 = children(element);
  4438. if (children$1.length === 0) {
  4439. return point(element, offset);
  4440. } else if (offset < children$1.length) {
  4441. return point(children$1[offset], 0);
  4442. } else {
  4443. const last = children$1[children$1.length - 1];
  4444. const len = isText(last) ? get$4(last).length : children(last).length;
  4445. return point(last, len);
  4446. }
  4447. };
  4448. const descendOnce = (element, offset) => isText(element) ? point(element, offset) : descendOnce$1(element, offset);
  4449. const getAnchorSelection = (win, anchorInfo) => {
  4450. const getSelection = anchorInfo.getSelection.getOrThunk(() => () => getExact(win));
  4451. return getSelection().map(sel => {
  4452. const modStart = descendOnce(sel.start, sel.soffset);
  4453. const modFinish = descendOnce(sel.finish, sel.foffset);
  4454. return SimSelection.range(modStart.element, modStart.offset, modFinish.element, modFinish.offset);
  4455. });
  4456. };
  4457. const placement$1 = (component, anchorInfo, origin) => {
  4458. const win = defaultView(anchorInfo.root).dom;
  4459. const rootPoint = getRootPoint(component, origin, anchorInfo);
  4460. const selectionBox = getAnchorSelection(win, anchorInfo).bind(sel => {
  4461. const optRect = getBounds$1(win, SimSelection.exactFromRange(sel)).orThunk(() => {
  4462. const x = SugarElement.fromText(zeroWidth);
  4463. before$1(sel.start, x);
  4464. const rect = getFirstRect(win, SimSelection.exact(x, 0, x, 1));
  4465. remove$5(x);
  4466. return rect;
  4467. });
  4468. return optRect.bind(rawRect => getBox(rawRect.left, rawRect.top, rawRect.width, rawRect.height));
  4469. });
  4470. const targetElement = getAnchorSelection(win, anchorInfo).bind(sel => isElement$1(sel.start) ? Optional.some(sel.start) : parentElement(sel.start));
  4471. const elem = targetElement.getOr(component.element);
  4472. return calcNewAnchor(selectionBox, rootPoint, anchorInfo, origin, elem);
  4473. };
  4474. var SelectionAnchor = [
  4475. option$3('getSelection'),
  4476. required$1('root'),
  4477. option$3('bubble'),
  4478. schema$y(),
  4479. defaulted('overrides', {}),
  4480. defaulted('showAbove', false),
  4481. output$1('placement', placement$1)
  4482. ];
  4483. const labelPrefix$1 = 'link-layout';
  4484. const eastX = anchor => anchor.x + anchor.width;
  4485. const westX = (anchor, element) => anchor.x - element.width;
  4486. const northY$1 = (anchor, element) => anchor.y - element.height + anchor.height;
  4487. const southY$1 = anchor => anchor.y;
  4488. const southeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), southY$1(anchor), bubbles.southeast(), southeast$3(), 'southeast', boundsRestriction(anchor, {
  4489. left: 0,
  4490. top: 2
  4491. }), labelPrefix$1);
  4492. const southwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), southY$1(anchor), bubbles.southwest(), southwest$3(), 'southwest', boundsRestriction(anchor, {
  4493. right: 1,
  4494. top: 2
  4495. }), labelPrefix$1);
  4496. const northeast$1 = (anchor, element, bubbles) => nu$6(eastX(anchor), northY$1(anchor, element), bubbles.northeast(), northeast$3(), 'northeast', boundsRestriction(anchor, {
  4497. left: 0,
  4498. bottom: 3
  4499. }), labelPrefix$1);
  4500. const northwest$1 = (anchor, element, bubbles) => nu$6(westX(anchor, element), northY$1(anchor, element), bubbles.northwest(), northwest$3(), 'northwest', boundsRestriction(anchor, {
  4501. right: 1,
  4502. bottom: 3
  4503. }), labelPrefix$1);
  4504. const all = () => [
  4505. southeast$1,
  4506. southwest$1,
  4507. northeast$1,
  4508. northwest$1
  4509. ];
  4510. const allRtl = () => [
  4511. southwest$1,
  4512. southeast$1,
  4513. northwest$1,
  4514. northeast$1
  4515. ];
  4516. const placement = (component, submenuInfo, origin) => {
  4517. const anchorBox = toBox(origin, submenuInfo.item.element);
  4518. const layouts = get$5(component.element, submenuInfo, all(), allRtl(), all(), allRtl(), Optional.none());
  4519. return Optional.some(nu$4({
  4520. anchorBox,
  4521. bubble: fallback(),
  4522. overrides: submenuInfo.overrides,
  4523. layouts,
  4524. placer: Optional.none()
  4525. }));
  4526. };
  4527. var SubmenuAnchor = [
  4528. required$1('item'),
  4529. schema$y(),
  4530. defaulted('overrides', {}),
  4531. output$1('placement', placement)
  4532. ];
  4533. var AnchorSchema = choose$1('type', {
  4534. selection: SelectionAnchor,
  4535. node: NodeAnchor,
  4536. hotspot: HotspotAnchor,
  4537. submenu: SubmenuAnchor,
  4538. makeshift: MakeshiftAnchor
  4539. });
  4540. const TransitionSchema = [
  4541. requiredArrayOf('classes', string),
  4542. defaultedStringEnum('mode', 'all', [
  4543. 'all',
  4544. 'layout',
  4545. 'placement'
  4546. ])
  4547. ];
  4548. const PositionSchema = [
  4549. defaulted('useFixed', never),
  4550. option$3('getBounds')
  4551. ];
  4552. const PlacementSchema = [
  4553. requiredOf('anchor', AnchorSchema),
  4554. optionObjOf('transition', TransitionSchema)
  4555. ];
  4556. const getFixedOrigin = () => {
  4557. const html = document.documentElement;
  4558. return fixed$1(0, 0, html.clientWidth, html.clientHeight);
  4559. };
  4560. const getRelativeOrigin = component => {
  4561. const position = absolute$3(component.element);
  4562. const bounds = component.element.dom.getBoundingClientRect();
  4563. return relative$1(position.left, position.top, bounds.width, bounds.height);
  4564. };
  4565. const place = (component, origin, anchoring, getBounds, placee, lastPlace, transition) => {
  4566. const anchor = box(anchoring.anchorBox, origin);
  4567. return simple(anchor, placee.element, anchoring.bubble, anchoring.layouts, lastPlace, getBounds, anchoring.overrides, transition);
  4568. };
  4569. const position$1 = (component, posConfig, posState, placee, placementSpec) => {
  4570. positionWithin(component, posConfig, posState, placee, placementSpec, Optional.none());
  4571. };
  4572. const positionWithin = (component, posConfig, posState, placee, placementSpec, boxElement) => {
  4573. const boundsBox = boxElement.map(box$1);
  4574. return positionWithinBounds(component, posConfig, posState, placee, placementSpec, boundsBox);
  4575. };
  4576. const positionWithinBounds = (component, posConfig, posState, placee, placementSpec, bounds) => {
  4577. const placeeDetail = asRawOrDie$1('placement.info', objOf(PlacementSchema), placementSpec);
  4578. const anchorage = placeeDetail.anchor;
  4579. const element = placee.element;
  4580. const placeeState = posState.get(placee.uid);
  4581. preserve$1(() => {
  4582. set$8(element, 'position', 'fixed');
  4583. const oldVisibility = getRaw(element, 'visibility');
  4584. set$8(element, 'visibility', 'hidden');
  4585. const origin = posConfig.useFixed() ? getFixedOrigin() : getRelativeOrigin(component);
  4586. const placer = anchorage.placement;
  4587. const getBounds = bounds.map(constant$1).or(posConfig.getBounds);
  4588. placer(component, anchorage, origin).each(anchoring => {
  4589. const doPlace = anchoring.placer.getOr(place);
  4590. const newState = doPlace(component, origin, anchoring, getBounds, placee, placeeState, placeeDetail.transition);
  4591. posState.set(placee.uid, newState);
  4592. });
  4593. oldVisibility.fold(() => {
  4594. remove$6(element, 'visibility');
  4595. }, vis => {
  4596. set$8(element, 'visibility', vis);
  4597. });
  4598. if (getRaw(element, 'left').isNone() && getRaw(element, 'top').isNone() && getRaw(element, 'right').isNone() && getRaw(element, 'bottom').isNone() && is$1(getRaw(element, 'position'), 'fixed')) {
  4599. remove$6(element, 'position');
  4600. }
  4601. }, element);
  4602. };
  4603. const getMode = (component, pConfig, _pState) => pConfig.useFixed() ? 'fixed' : 'absolute';
  4604. const reset$1 = (component, pConfig, posState, placee) => {
  4605. const element = placee.element;
  4606. each$1([
  4607. 'position',
  4608. 'left',
  4609. 'right',
  4610. 'top',
  4611. 'bottom'
  4612. ], prop => remove$6(element, prop));
  4613. reset$2(element);
  4614. posState.clear(placee.uid);
  4615. };
  4616. var PositionApis = /*#__PURE__*/Object.freeze({
  4617. __proto__: null,
  4618. position: position$1,
  4619. positionWithin: positionWithin,
  4620. positionWithinBounds: positionWithinBounds,
  4621. getMode: getMode,
  4622. reset: reset$1
  4623. });
  4624. const init$g = () => {
  4625. let state = {};
  4626. const set = (id, data) => {
  4627. state[id] = data;
  4628. };
  4629. const get = id => get$g(state, id);
  4630. const clear = id => {
  4631. if (isNonNullable(id)) {
  4632. delete state[id];
  4633. } else {
  4634. state = {};
  4635. }
  4636. };
  4637. return nu$8({
  4638. readState: () => state,
  4639. clear,
  4640. set,
  4641. get
  4642. });
  4643. };
  4644. var PositioningState = /*#__PURE__*/Object.freeze({
  4645. __proto__: null,
  4646. init: init$g
  4647. });
  4648. const Positioning = create$3({
  4649. fields: PositionSchema,
  4650. name: 'positioning',
  4651. active: ActivePosition,
  4652. apis: PositionApis,
  4653. state: PositioningState
  4654. });
  4655. const isConnected = comp => comp.getSystem().isConnected();
  4656. const fireDetaching = component => {
  4657. emit(component, detachedFromDom());
  4658. const children = component.components();
  4659. each$1(children, fireDetaching);
  4660. };
  4661. const fireAttaching = component => {
  4662. const children = component.components();
  4663. each$1(children, fireAttaching);
  4664. emit(component, attachedToDom());
  4665. };
  4666. const virtualAttach = (parent, child) => {
  4667. parent.getSystem().addToWorld(child);
  4668. if (inBody(parent.element)) {
  4669. fireAttaching(child);
  4670. }
  4671. };
  4672. const virtualDetach = comp => {
  4673. fireDetaching(comp);
  4674. comp.getSystem().removeFromWorld(comp);
  4675. };
  4676. const attach$1 = (parent, child) => {
  4677. append$2(parent.element, child.element);
  4678. };
  4679. const detachChildren$1 = component => {
  4680. each$1(component.components(), childComp => remove$5(childComp.element));
  4681. empty(component.element);
  4682. component.syncComponents();
  4683. };
  4684. const replaceChildren = (component, newSpecs, buildNewChildren) => {
  4685. const subs = component.components();
  4686. detachChildren$1(component);
  4687. const newChildren = buildNewChildren(newSpecs);
  4688. const deleted = difference(subs, newChildren);
  4689. each$1(deleted, comp => {
  4690. fireDetaching(comp);
  4691. component.getSystem().removeFromWorld(comp);
  4692. });
  4693. each$1(newChildren, childComp => {
  4694. if (!isConnected(childComp)) {
  4695. component.getSystem().addToWorld(childComp);
  4696. attach$1(component, childComp);
  4697. if (inBody(component.element)) {
  4698. fireAttaching(childComp);
  4699. }
  4700. } else {
  4701. attach$1(component, childComp);
  4702. }
  4703. });
  4704. component.syncComponents();
  4705. };
  4706. const virtualReplaceChildren = (component, newSpecs, buildNewChildren) => {
  4707. const subs = component.components();
  4708. const existingComps = bind$3(newSpecs, spec => getPremade(spec).toArray());
  4709. each$1(subs, childComp => {
  4710. if (!contains$2(existingComps, childComp)) {
  4711. virtualDetach(childComp);
  4712. }
  4713. });
  4714. const newChildren = buildNewChildren(newSpecs);
  4715. const deleted = difference(subs, newChildren);
  4716. each$1(deleted, deletedComp => {
  4717. if (isConnected(deletedComp)) {
  4718. virtualDetach(deletedComp);
  4719. }
  4720. });
  4721. each$1(newChildren, childComp => {
  4722. if (!isConnected(childComp)) {
  4723. virtualAttach(component, childComp);
  4724. }
  4725. });
  4726. component.syncComponents();
  4727. };
  4728. const attach = (parent, child) => {
  4729. attachWith(parent, child, append$2);
  4730. };
  4731. const attachWith = (parent, child, insertion) => {
  4732. parent.getSystem().addToWorld(child);
  4733. insertion(parent.element, child.element);
  4734. if (inBody(parent.element)) {
  4735. fireAttaching(child);
  4736. }
  4737. parent.syncComponents();
  4738. };
  4739. const doDetach = component => {
  4740. fireDetaching(component);
  4741. remove$5(component.element);
  4742. component.getSystem().removeFromWorld(component);
  4743. };
  4744. const detach = component => {
  4745. const parent$1 = parent(component.element).bind(p => component.getSystem().getByDom(p).toOptional());
  4746. doDetach(component);
  4747. parent$1.each(p => {
  4748. p.syncComponents();
  4749. });
  4750. };
  4751. const detachChildren = component => {
  4752. const subs = component.components();
  4753. each$1(subs, doDetach);
  4754. empty(component.element);
  4755. component.syncComponents();
  4756. };
  4757. const attachSystem = (element, guiSystem) => {
  4758. attachSystemWith(element, guiSystem, append$2);
  4759. };
  4760. const attachSystemAfter = (element, guiSystem) => {
  4761. attachSystemWith(element, guiSystem, after$2);
  4762. };
  4763. const attachSystemWith = (element, guiSystem, inserter) => {
  4764. inserter(element, guiSystem.element);
  4765. const children$1 = children(guiSystem.element);
  4766. each$1(children$1, child => {
  4767. guiSystem.getByDom(child).each(fireAttaching);
  4768. });
  4769. };
  4770. const detachSystem = guiSystem => {
  4771. const children$1 = children(guiSystem.element);
  4772. each$1(children$1, child => {
  4773. guiSystem.getByDom(child).each(fireDetaching);
  4774. });
  4775. remove$5(guiSystem.element);
  4776. };
  4777. const rebuild = (sandbox, sConfig, sState, data) => {
  4778. sState.get().each(_data => {
  4779. detachChildren(sandbox);
  4780. });
  4781. const point = sConfig.getAttachPoint(sandbox);
  4782. attach(point, sandbox);
  4783. const built = sandbox.getSystem().build(data);
  4784. attach(sandbox, built);
  4785. sState.set(built);
  4786. return built;
  4787. };
  4788. const open$1 = (sandbox, sConfig, sState, data) => {
  4789. const newState = rebuild(sandbox, sConfig, sState, data);
  4790. sConfig.onOpen(sandbox, newState);
  4791. return newState;
  4792. };
  4793. const setContent = (sandbox, sConfig, sState, data) => sState.get().map(() => rebuild(sandbox, sConfig, sState, data));
  4794. const openWhileCloaked = (sandbox, sConfig, sState, data, transaction) => {
  4795. cloak(sandbox, sConfig);
  4796. open$1(sandbox, sConfig, sState, data);
  4797. transaction();
  4798. decloak(sandbox, sConfig);
  4799. };
  4800. const close$1 = (sandbox, sConfig, sState) => {
  4801. sState.get().each(data => {
  4802. detachChildren(sandbox);
  4803. detach(sandbox);
  4804. sConfig.onClose(sandbox, data);
  4805. sState.clear();
  4806. });
  4807. };
  4808. const isOpen$1 = (_sandbox, _sConfig, sState) => sState.isOpen();
  4809. const isPartOf = (sandbox, sConfig, sState, queryElem) => isOpen$1(sandbox, sConfig, sState) && sState.get().exists(data => sConfig.isPartOf(sandbox, data, queryElem));
  4810. const getState$2 = (_sandbox, _sConfig, sState) => sState.get();
  4811. const store = (sandbox, cssKey, attr, newValue) => {
  4812. getRaw(sandbox.element, cssKey).fold(() => {
  4813. remove$7(sandbox.element, attr);
  4814. }, v => {
  4815. set$9(sandbox.element, attr, v);
  4816. });
  4817. set$8(sandbox.element, cssKey, newValue);
  4818. };
  4819. const restore = (sandbox, cssKey, attr) => {
  4820. getOpt(sandbox.element, attr).fold(() => remove$6(sandbox.element, cssKey), oldValue => set$8(sandbox.element, cssKey, oldValue));
  4821. };
  4822. const cloak = (sandbox, sConfig, _sState) => {
  4823. const sink = sConfig.getAttachPoint(sandbox);
  4824. set$8(sandbox.element, 'position', Positioning.getMode(sink));
  4825. store(sandbox, 'visibility', sConfig.cloakVisibilityAttr, 'hidden');
  4826. };
  4827. const hasPosition = element => exists([
  4828. 'top',
  4829. 'left',
  4830. 'right',
  4831. 'bottom'
  4832. ], pos => getRaw(element, pos).isSome());
  4833. const decloak = (sandbox, sConfig, _sState) => {
  4834. if (!hasPosition(sandbox.element)) {
  4835. remove$6(sandbox.element, 'position');
  4836. }
  4837. restore(sandbox, 'visibility', sConfig.cloakVisibilityAttr);
  4838. };
  4839. var SandboxApis = /*#__PURE__*/Object.freeze({
  4840. __proto__: null,
  4841. cloak: cloak,
  4842. decloak: decloak,
  4843. open: open$1,
  4844. openWhileCloaked: openWhileCloaked,
  4845. close: close$1,
  4846. isOpen: isOpen$1,
  4847. isPartOf: isPartOf,
  4848. getState: getState$2,
  4849. setContent: setContent
  4850. });
  4851. const events$g = (sandboxConfig, sandboxState) => derive$2([run$1(sandboxClose(), (sandbox, _simulatedEvent) => {
  4852. close$1(sandbox, sandboxConfig, sandboxState);
  4853. })]);
  4854. var ActiveSandbox = /*#__PURE__*/Object.freeze({
  4855. __proto__: null,
  4856. events: events$g
  4857. });
  4858. var SandboxSchema = [
  4859. onHandler('onOpen'),
  4860. onHandler('onClose'),
  4861. required$1('isPartOf'),
  4862. required$1('getAttachPoint'),
  4863. defaulted('cloakVisibilityAttr', 'data-precloak-visibility')
  4864. ];
  4865. const init$f = () => {
  4866. const contents = value$2();
  4867. const readState = constant$1('not-implemented');
  4868. return nu$8({
  4869. readState,
  4870. isOpen: contents.isSet,
  4871. clear: contents.clear,
  4872. set: contents.set,
  4873. get: contents.get
  4874. });
  4875. };
  4876. var SandboxState = /*#__PURE__*/Object.freeze({
  4877. __proto__: null,
  4878. init: init$f
  4879. });
  4880. const Sandboxing = create$3({
  4881. fields: SandboxSchema,
  4882. name: 'sandboxing',
  4883. active: ActiveSandbox,
  4884. apis: SandboxApis,
  4885. state: SandboxState
  4886. });
  4887. const dismissPopups = constant$1('dismiss.popups');
  4888. const repositionPopups = constant$1('reposition.popups');
  4889. const mouseReleased = constant$1('mouse.released');
  4890. const schema$x = objOfOnly([
  4891. defaulted('isExtraPart', never),
  4892. optionObjOf('fireEventInstead', [defaulted('event', dismissRequested())])
  4893. ]);
  4894. const receivingChannel$1 = rawSpec => {
  4895. const detail = asRawOrDie$1('Dismissal', schema$x, rawSpec);
  4896. return {
  4897. [dismissPopups()]: {
  4898. schema: objOfOnly([required$1('target')]),
  4899. onReceive: (sandbox, data) => {
  4900. if (Sandboxing.isOpen(sandbox)) {
  4901. const isPart = Sandboxing.isPartOf(sandbox, data.target) || detail.isExtraPart(sandbox, data.target);
  4902. if (!isPart) {
  4903. detail.fireEventInstead.fold(() => Sandboxing.close(sandbox), fe => emit(sandbox, fe.event));
  4904. }
  4905. }
  4906. }
  4907. }
  4908. };
  4909. };
  4910. const schema$w = objOfOnly([
  4911. optionObjOf('fireEventInstead', [defaulted('event', repositionRequested())]),
  4912. requiredFunction('doReposition')
  4913. ]);
  4914. const receivingChannel = rawSpec => {
  4915. const detail = asRawOrDie$1('Reposition', schema$w, rawSpec);
  4916. return {
  4917. [repositionPopups()]: {
  4918. onReceive: sandbox => {
  4919. if (Sandboxing.isOpen(sandbox)) {
  4920. detail.fireEventInstead.fold(() => detail.doReposition(sandbox), fe => emit(sandbox, fe.event));
  4921. }
  4922. }
  4923. }
  4924. };
  4925. };
  4926. const onLoad$5 = (component, repConfig, repState) => {
  4927. repConfig.store.manager.onLoad(component, repConfig, repState);
  4928. };
  4929. const onUnload$2 = (component, repConfig, repState) => {
  4930. repConfig.store.manager.onUnload(component, repConfig, repState);
  4931. };
  4932. const setValue$3 = (component, repConfig, repState, data) => {
  4933. repConfig.store.manager.setValue(component, repConfig, repState, data);
  4934. };
  4935. const getValue$3 = (component, repConfig, repState) => repConfig.store.manager.getValue(component, repConfig, repState);
  4936. const getState$1 = (component, repConfig, repState) => repState;
  4937. var RepresentApis = /*#__PURE__*/Object.freeze({
  4938. __proto__: null,
  4939. onLoad: onLoad$5,
  4940. onUnload: onUnload$2,
  4941. setValue: setValue$3,
  4942. getValue: getValue$3,
  4943. getState: getState$1
  4944. });
  4945. const events$f = (repConfig, repState) => {
  4946. const es = repConfig.resetOnDom ? [
  4947. runOnAttached((comp, _se) => {
  4948. onLoad$5(comp, repConfig, repState);
  4949. }),
  4950. runOnDetached((comp, _se) => {
  4951. onUnload$2(comp, repConfig, repState);
  4952. })
  4953. ] : [loadEvent(repConfig, repState, onLoad$5)];
  4954. return derive$2(es);
  4955. };
  4956. var ActiveRepresenting = /*#__PURE__*/Object.freeze({
  4957. __proto__: null,
  4958. events: events$f
  4959. });
  4960. const memory$1 = () => {
  4961. const data = Cell(null);
  4962. const readState = () => ({
  4963. mode: 'memory',
  4964. value: data.get()
  4965. });
  4966. const isNotSet = () => data.get() === null;
  4967. const clear = () => {
  4968. data.set(null);
  4969. };
  4970. return nu$8({
  4971. set: data.set,
  4972. get: data.get,
  4973. isNotSet,
  4974. clear,
  4975. readState
  4976. });
  4977. };
  4978. const manual = () => {
  4979. const readState = noop;
  4980. return nu$8({ readState });
  4981. };
  4982. const dataset = () => {
  4983. const dataByValue = Cell({});
  4984. const dataByText = Cell({});
  4985. const readState = () => ({
  4986. mode: 'dataset',
  4987. dataByValue: dataByValue.get(),
  4988. dataByText: dataByText.get()
  4989. });
  4990. const clear = () => {
  4991. dataByValue.set({});
  4992. dataByText.set({});
  4993. };
  4994. const lookup = itemString => get$g(dataByValue.get(), itemString).orThunk(() => get$g(dataByText.get(), itemString));
  4995. const update = items => {
  4996. const currentDataByValue = dataByValue.get();
  4997. const currentDataByText = dataByText.get();
  4998. const newDataByValue = {};
  4999. const newDataByText = {};
  5000. each$1(items, item => {
  5001. newDataByValue[item.value] = item;
  5002. get$g(item, 'meta').each(meta => {
  5003. get$g(meta, 'text').each(text => {
  5004. newDataByText[text] = item;
  5005. });
  5006. });
  5007. });
  5008. dataByValue.set({
  5009. ...currentDataByValue,
  5010. ...newDataByValue
  5011. });
  5012. dataByText.set({
  5013. ...currentDataByText,
  5014. ...newDataByText
  5015. });
  5016. };
  5017. return nu$8({
  5018. readState,
  5019. lookup,
  5020. update,
  5021. clear
  5022. });
  5023. };
  5024. const init$e = spec => spec.store.manager.state(spec);
  5025. var RepresentState = /*#__PURE__*/Object.freeze({
  5026. __proto__: null,
  5027. memory: memory$1,
  5028. dataset: dataset,
  5029. manual: manual,
  5030. init: init$e
  5031. });
  5032. const setValue$2 = (component, repConfig, repState, data) => {
  5033. const store = repConfig.store;
  5034. repState.update([data]);
  5035. store.setValue(component, data);
  5036. repConfig.onSetValue(component, data);
  5037. };
  5038. const getValue$2 = (component, repConfig, repState) => {
  5039. const store = repConfig.store;
  5040. const key = store.getDataKey(component);
  5041. return repState.lookup(key).getOrThunk(() => store.getFallbackEntry(key));
  5042. };
  5043. const onLoad$4 = (component, repConfig, repState) => {
  5044. const store = repConfig.store;
  5045. store.initialValue.each(data => {
  5046. setValue$2(component, repConfig, repState, data);
  5047. });
  5048. };
  5049. const onUnload$1 = (component, repConfig, repState) => {
  5050. repState.clear();
  5051. };
  5052. var DatasetStore = [
  5053. option$3('initialValue'),
  5054. required$1('getFallbackEntry'),
  5055. required$1('getDataKey'),
  5056. required$1('setValue'),
  5057. output$1('manager', {
  5058. setValue: setValue$2,
  5059. getValue: getValue$2,
  5060. onLoad: onLoad$4,
  5061. onUnload: onUnload$1,
  5062. state: dataset
  5063. })
  5064. ];
  5065. const getValue$1 = (component, repConfig, _repState) => repConfig.store.getValue(component);
  5066. const setValue$1 = (component, repConfig, _repState, data) => {
  5067. repConfig.store.setValue(component, data);
  5068. repConfig.onSetValue(component, data);
  5069. };
  5070. const onLoad$3 = (component, repConfig, _repState) => {
  5071. repConfig.store.initialValue.each(data => {
  5072. repConfig.store.setValue(component, data);
  5073. });
  5074. };
  5075. var ManualStore = [
  5076. required$1('getValue'),
  5077. defaulted('setValue', noop),
  5078. option$3('initialValue'),
  5079. output$1('manager', {
  5080. setValue: setValue$1,
  5081. getValue: getValue$1,
  5082. onLoad: onLoad$3,
  5083. onUnload: noop,
  5084. state: NoState.init
  5085. })
  5086. ];
  5087. const setValue = (component, repConfig, repState, data) => {
  5088. repState.set(data);
  5089. repConfig.onSetValue(component, data);
  5090. };
  5091. const getValue = (component, repConfig, repState) => repState.get();
  5092. const onLoad$2 = (component, repConfig, repState) => {
  5093. repConfig.store.initialValue.each(initVal => {
  5094. if (repState.isNotSet()) {
  5095. repState.set(initVal);
  5096. }
  5097. });
  5098. };
  5099. const onUnload = (component, repConfig, repState) => {
  5100. repState.clear();
  5101. };
  5102. var MemoryStore = [
  5103. option$3('initialValue'),
  5104. output$1('manager', {
  5105. setValue,
  5106. getValue,
  5107. onLoad: onLoad$2,
  5108. onUnload,
  5109. state: memory$1
  5110. })
  5111. ];
  5112. var RepresentSchema = [
  5113. defaultedOf('store', { mode: 'memory' }, choose$1('mode', {
  5114. memory: MemoryStore,
  5115. manual: ManualStore,
  5116. dataset: DatasetStore
  5117. })),
  5118. onHandler('onSetValue'),
  5119. defaulted('resetOnDom', false)
  5120. ];
  5121. const Representing = create$3({
  5122. fields: RepresentSchema,
  5123. name: 'representing',
  5124. active: ActiveRepresenting,
  5125. apis: RepresentApis,
  5126. extra: {
  5127. setValueFrom: (component, source) => {
  5128. const value = Representing.getValue(source);
  5129. Representing.setValue(component, value);
  5130. }
  5131. },
  5132. state: RepresentState
  5133. });
  5134. const field = (name, forbidden) => defaultedObjOf(name, {}, map$2(forbidden, f => forbid(f.name(), 'Cannot configure ' + f.name() + ' for ' + name)).concat([customField('dump', identity)]));
  5135. const get$3 = data => data.dump;
  5136. const augment = (data, original) => ({
  5137. ...derive$1(original),
  5138. ...data.dump
  5139. });
  5140. const SketchBehaviours = {
  5141. field,
  5142. augment,
  5143. get: get$3
  5144. };
  5145. const _placeholder = 'placeholder';
  5146. const adt$3 = Adt.generate([
  5147. {
  5148. single: [
  5149. 'required',
  5150. 'valueThunk'
  5151. ]
  5152. },
  5153. {
  5154. multiple: [
  5155. 'required',
  5156. 'valueThunks'
  5157. ]
  5158. }
  5159. ]);
  5160. const isSubstituted = spec => has$2(spec, 'uiType');
  5161. const subPlaceholder = (owner, detail, compSpec, placeholders) => {
  5162. if (owner.exists(o => o !== compSpec.owner)) {
  5163. return adt$3.single(true, constant$1(compSpec));
  5164. }
  5165. return get$g(placeholders, compSpec.name).fold(() => {
  5166. throw new Error('Unknown placeholder component: ' + compSpec.name + '\nKnown: [' + keys(placeholders) + ']\nNamespace: ' + owner.getOr('none') + '\nSpec: ' + JSON.stringify(compSpec, null, 2));
  5167. }, newSpec => newSpec.replace());
  5168. };
  5169. const scan = (owner, detail, compSpec, placeholders) => {
  5170. if (isSubstituted(compSpec) && compSpec.uiType === _placeholder) {
  5171. return subPlaceholder(owner, detail, compSpec, placeholders);
  5172. } else {
  5173. return adt$3.single(false, constant$1(compSpec));
  5174. }
  5175. };
  5176. const substitute = (owner, detail, compSpec, placeholders) => {
  5177. const base = scan(owner, detail, compSpec, placeholders);
  5178. return base.fold((req, valueThunk) => {
  5179. const value = isSubstituted(compSpec) ? valueThunk(detail, compSpec.config, compSpec.validated) : valueThunk(detail);
  5180. const childSpecs = get$g(value, 'components').getOr([]);
  5181. const substituted = bind$3(childSpecs, c => substitute(owner, detail, c, placeholders));
  5182. return [{
  5183. ...value,
  5184. components: substituted
  5185. }];
  5186. }, (req, valuesThunk) => {
  5187. if (isSubstituted(compSpec)) {
  5188. const values = valuesThunk(detail, compSpec.config, compSpec.validated);
  5189. const preprocessor = compSpec.validated.preprocess.getOr(identity);
  5190. return preprocessor(values);
  5191. } else {
  5192. return valuesThunk(detail);
  5193. }
  5194. });
  5195. };
  5196. const substituteAll = (owner, detail, components, placeholders) => bind$3(components, c => substitute(owner, detail, c, placeholders));
  5197. const oneReplace = (label, replacements) => {
  5198. let called = false;
  5199. const used = () => called;
  5200. const replace = () => {
  5201. if (called) {
  5202. throw new Error('Trying to use the same placeholder more than once: ' + label);
  5203. }
  5204. called = true;
  5205. return replacements;
  5206. };
  5207. const required = () => replacements.fold((req, _) => req, (req, _) => req);
  5208. return {
  5209. name: constant$1(label),
  5210. required,
  5211. used,
  5212. replace
  5213. };
  5214. };
  5215. const substitutePlaces = (owner, detail, components, placeholders) => {
  5216. const ps = map$1(placeholders, (ph, name) => oneReplace(name, ph));
  5217. const outcome = substituteAll(owner, detail, components, ps);
  5218. each(ps, p => {
  5219. if (p.used() === false && p.required()) {
  5220. throw new Error('Placeholder: ' + p.name() + ' was not found in components list\nNamespace: ' + owner.getOr('none') + '\nComponents: ' + JSON.stringify(detail.components, null, 2));
  5221. }
  5222. });
  5223. return outcome;
  5224. };
  5225. const single$2 = adt$3.single;
  5226. const multiple = adt$3.multiple;
  5227. const placeholder = constant$1(_placeholder);
  5228. const adt$2 = Adt.generate([
  5229. { required: ['data'] },
  5230. { external: ['data'] },
  5231. { optional: ['data'] },
  5232. { group: ['data'] }
  5233. ]);
  5234. const fFactory = defaulted('factory', { sketch: identity });
  5235. const fSchema = defaulted('schema', []);
  5236. const fName = required$1('name');
  5237. const fPname = field$1('pname', 'pname', defaultedThunk(typeSpec => '<alloy.' + generate$6(typeSpec.name) + '>'), anyValue());
  5238. const fGroupSchema = customField('schema', () => [option$3('preprocess')]);
  5239. const fDefaults = defaulted('defaults', constant$1({}));
  5240. const fOverrides = defaulted('overrides', constant$1({}));
  5241. const requiredSpec = objOf([
  5242. fFactory,
  5243. fSchema,
  5244. fName,
  5245. fPname,
  5246. fDefaults,
  5247. fOverrides
  5248. ]);
  5249. const externalSpec = objOf([
  5250. fFactory,
  5251. fSchema,
  5252. fName,
  5253. fDefaults,
  5254. fOverrides
  5255. ]);
  5256. const optionalSpec = objOf([
  5257. fFactory,
  5258. fSchema,
  5259. fName,
  5260. fPname,
  5261. fDefaults,
  5262. fOverrides
  5263. ]);
  5264. const groupSpec = objOf([
  5265. fFactory,
  5266. fGroupSchema,
  5267. fName,
  5268. required$1('unit'),
  5269. fPname,
  5270. fDefaults,
  5271. fOverrides
  5272. ]);
  5273. const asNamedPart = part => {
  5274. return part.fold(Optional.some, Optional.none, Optional.some, Optional.some);
  5275. };
  5276. const name$2 = part => {
  5277. const get = data => data.name;
  5278. return part.fold(get, get, get, get);
  5279. };
  5280. const asCommon = part => {
  5281. return part.fold(identity, identity, identity, identity);
  5282. };
  5283. const convert = (adtConstructor, partSchema) => spec => {
  5284. const data = asRawOrDie$1('Converting part type', partSchema, spec);
  5285. return adtConstructor(data);
  5286. };
  5287. const required = convert(adt$2.required, requiredSpec);
  5288. const external = convert(adt$2.external, externalSpec);
  5289. const optional = convert(adt$2.optional, optionalSpec);
  5290. const group = convert(adt$2.group, groupSpec);
  5291. const original = constant$1('entirety');
  5292. var PartType = /*#__PURE__*/Object.freeze({
  5293. __proto__: null,
  5294. required: required,
  5295. external: external,
  5296. optional: optional,
  5297. group: group,
  5298. asNamedPart: asNamedPart,
  5299. name: name$2,
  5300. asCommon: asCommon,
  5301. original: original
  5302. });
  5303. const combine = (detail, data, partSpec, partValidated) => deepMerge(data.defaults(detail, partSpec, partValidated), partSpec, { uid: detail.partUids[data.name] }, data.overrides(detail, partSpec, partValidated));
  5304. const subs = (owner, detail, parts) => {
  5305. const internals = {};
  5306. const externals = {};
  5307. each$1(parts, part => {
  5308. part.fold(data => {
  5309. internals[data.pname] = single$2(true, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
  5310. }, data => {
  5311. const partSpec = detail.parts[data.name];
  5312. externals[data.name] = constant$1(data.factory.sketch(combine(detail, data, partSpec[original()]), partSpec));
  5313. }, data => {
  5314. internals[data.pname] = single$2(false, (detail, partSpec, partValidated) => data.factory.sketch(combine(detail, data, partSpec, partValidated)));
  5315. }, data => {
  5316. internals[data.pname] = multiple(true, (detail, _partSpec, _partValidated) => {
  5317. const units = detail[data.name];
  5318. return map$2(units, u => data.factory.sketch(deepMerge(data.defaults(detail, u, _partValidated), u, data.overrides(detail, u))));
  5319. });
  5320. });
  5321. });
  5322. return {
  5323. internals: constant$1(internals),
  5324. externals: constant$1(externals)
  5325. };
  5326. };
  5327. const generate$3 = (owner, parts) => {
  5328. const r = {};
  5329. each$1(parts, part => {
  5330. asNamedPart(part).each(np => {
  5331. const g = doGenerateOne(owner, np.pname);
  5332. r[np.name] = config => {
  5333. const validated = asRawOrDie$1('Part: ' + np.name + ' in ' + owner, objOf(np.schema), config);
  5334. return {
  5335. ...g,
  5336. config,
  5337. validated
  5338. };
  5339. };
  5340. });
  5341. });
  5342. return r;
  5343. };
  5344. const doGenerateOne = (owner, pname) => ({
  5345. uiType: placeholder(),
  5346. owner,
  5347. name: pname
  5348. });
  5349. const generateOne$1 = (owner, pname, config) => ({
  5350. uiType: placeholder(),
  5351. owner,
  5352. name: pname,
  5353. config,
  5354. validated: {}
  5355. });
  5356. 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());
  5357. const names = parts => map$2(parts, name$2);
  5358. const substitutes = (owner, detail, parts) => subs(owner, detail, parts);
  5359. const components$1 = (owner, detail, internals) => substitutePlaces(Optional.some(owner), detail, detail.components, internals);
  5360. const getPart = (component, detail, partKey) => {
  5361. const uid = detail.partUids[partKey];
  5362. return component.getSystem().getByUid(uid).toOptional();
  5363. };
  5364. const getPartOrDie = (component, detail, partKey) => getPart(component, detail, partKey).getOrDie('Could not find part: ' + partKey);
  5365. const getParts = (component, detail, partKeys) => {
  5366. const r = {};
  5367. const uids = detail.partUids;
  5368. const system = component.getSystem();
  5369. each$1(partKeys, pk => {
  5370. r[pk] = constant$1(system.getByUid(uids[pk]));
  5371. });
  5372. return r;
  5373. };
  5374. const getAllParts = (component, detail) => {
  5375. const system = component.getSystem();
  5376. return map$1(detail.partUids, (pUid, _k) => constant$1(system.getByUid(pUid)));
  5377. };
  5378. const getAllPartNames = detail => keys(detail.partUids);
  5379. const getPartsOrDie = (component, detail, partKeys) => {
  5380. const r = {};
  5381. const uids = detail.partUids;
  5382. const system = component.getSystem();
  5383. each$1(partKeys, pk => {
  5384. r[pk] = constant$1(system.getByUid(uids[pk]).getOrDie());
  5385. });
  5386. return r;
  5387. };
  5388. const defaultUids = (baseUid, partTypes) => {
  5389. const partNames = names(partTypes);
  5390. return wrapAll(map$2(partNames, pn => ({
  5391. key: pn,
  5392. value: baseUid + '-' + pn
  5393. })));
  5394. };
  5395. const defaultUidsSchema = partTypes => field$1('partUids', 'partUids', mergeWithThunk(spec => defaultUids(spec.uid, partTypes)), anyValue());
  5396. var AlloyParts = /*#__PURE__*/Object.freeze({
  5397. __proto__: null,
  5398. generate: generate$3,
  5399. generateOne: generateOne$1,
  5400. schemas: schemas,
  5401. names: names,
  5402. substitutes: substitutes,
  5403. components: components$1,
  5404. defaultUids: defaultUids,
  5405. defaultUidsSchema: defaultUidsSchema,
  5406. getAllParts: getAllParts,
  5407. getAllPartNames: getAllPartNames,
  5408. getPart: getPart,
  5409. getPartOrDie: getPartOrDie,
  5410. getParts: getParts,
  5411. getPartsOrDie: getPartsOrDie
  5412. });
  5413. const base = (partSchemas, partUidsSchemas) => {
  5414. const ps = partSchemas.length > 0 ? [requiredObjOf('parts', partSchemas)] : [];
  5415. return ps.concat([
  5416. required$1('uid'),
  5417. defaulted('dom', {}),
  5418. defaulted('components', []),
  5419. snapshot('originalSpec'),
  5420. defaulted('debug.sketcher', {})
  5421. ]).concat(partUidsSchemas);
  5422. };
  5423. const asRawOrDie = (label, schema, spec, partSchemas, partUidsSchemas) => {
  5424. const baseS = base(partSchemas, partUidsSchemas);
  5425. return asRawOrDie$1(label + ' [SpecSchema]', objOfOnly(baseS.concat(schema)), spec);
  5426. };
  5427. const single$1 = (owner, schema, factory, spec) => {
  5428. const specWithUid = supplyUid(spec);
  5429. const detail = asRawOrDie(owner, schema, specWithUid, [], []);
  5430. return factory(detail, specWithUid);
  5431. };
  5432. const composite$1 = (owner, schema, partTypes, factory, spec) => {
  5433. const specWithUid = supplyUid(spec);
  5434. const partSchemas = schemas(partTypes);
  5435. const partUidsSchema = defaultUidsSchema(partTypes);
  5436. const detail = asRawOrDie(owner, schema, specWithUid, partSchemas, [partUidsSchema]);
  5437. const subs = substitutes(owner, detail, partTypes);
  5438. const components = components$1(owner, detail, subs.internals());
  5439. return factory(detail, components, specWithUid, subs.externals());
  5440. };
  5441. const hasUid = spec => has$2(spec, 'uid');
  5442. const supplyUid = spec => {
  5443. return hasUid(spec) ? spec : {
  5444. ...spec,
  5445. uid: generate$5('uid')
  5446. };
  5447. };
  5448. const isSketchSpec = spec => {
  5449. return spec.uid !== undefined;
  5450. };
  5451. const singleSchema = objOfOnly([
  5452. required$1('name'),
  5453. required$1('factory'),
  5454. required$1('configFields'),
  5455. defaulted('apis', {}),
  5456. defaulted('extraApis', {})
  5457. ]);
  5458. const compositeSchema = objOfOnly([
  5459. required$1('name'),
  5460. required$1('factory'),
  5461. required$1('configFields'),
  5462. required$1('partFields'),
  5463. defaulted('apis', {}),
  5464. defaulted('extraApis', {})
  5465. ]);
  5466. const single = rawConfig => {
  5467. const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, singleSchema, rawConfig);
  5468. const sketch = spec => single$1(config.name, config.configFields, config.factory, spec);
  5469. const apis = map$1(config.apis, makeApi);
  5470. const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
  5471. return {
  5472. name: config.name,
  5473. configFields: config.configFields,
  5474. sketch,
  5475. ...apis,
  5476. ...extraApis
  5477. };
  5478. };
  5479. const composite = rawConfig => {
  5480. const config = asRawOrDie$1('Sketcher for ' + rawConfig.name, compositeSchema, rawConfig);
  5481. const sketch = spec => composite$1(config.name, config.configFields, config.partFields, config.factory, spec);
  5482. const parts = generate$3(config.name, config.partFields);
  5483. const apis = map$1(config.apis, makeApi);
  5484. const extraApis = map$1(config.extraApis, (f, k) => markAsExtraApi(f, k));
  5485. return {
  5486. name: config.name,
  5487. partFields: config.partFields,
  5488. configFields: config.configFields,
  5489. sketch,
  5490. parts,
  5491. ...apis,
  5492. ...extraApis
  5493. };
  5494. };
  5495. const inside = target => isTag('input')(target) && get$f(target, 'type') !== 'radio' || isTag('textarea')(target);
  5496. const getCurrent = (component, composeConfig, _composeState) => composeConfig.find(component);
  5497. var ComposeApis = /*#__PURE__*/Object.freeze({
  5498. __proto__: null,
  5499. getCurrent: getCurrent
  5500. });
  5501. const ComposeSchema = [required$1('find')];
  5502. const Composing = create$3({
  5503. fields: ComposeSchema,
  5504. name: 'composing',
  5505. apis: ComposeApis
  5506. });
  5507. const nativeDisabled = [
  5508. 'input',
  5509. 'button',
  5510. 'textarea',
  5511. 'select'
  5512. ];
  5513. const onLoad$1 = (component, disableConfig, disableState) => {
  5514. const f = disableConfig.disabled() ? disable : enable;
  5515. f(component, disableConfig);
  5516. };
  5517. const hasNative = (component, config) => config.useNative === true && contains$2(nativeDisabled, name$3(component.element));
  5518. const nativeIsDisabled = component => has$1(component.element, 'disabled');
  5519. const nativeDisable = component => {
  5520. set$9(component.element, 'disabled', 'disabled');
  5521. };
  5522. const nativeEnable = component => {
  5523. remove$7(component.element, 'disabled');
  5524. };
  5525. const ariaIsDisabled = component => get$f(component.element, 'aria-disabled') === 'true';
  5526. const ariaDisable = component => {
  5527. set$9(component.element, 'aria-disabled', 'true');
  5528. };
  5529. const ariaEnable = component => {
  5530. set$9(component.element, 'aria-disabled', 'false');
  5531. };
  5532. const disable = (component, disableConfig, _disableState) => {
  5533. disableConfig.disableClass.each(disableClass => {
  5534. add$2(component.element, disableClass);
  5535. });
  5536. const f = hasNative(component, disableConfig) ? nativeDisable : ariaDisable;
  5537. f(component);
  5538. disableConfig.onDisabled(component);
  5539. };
  5540. const enable = (component, disableConfig, _disableState) => {
  5541. disableConfig.disableClass.each(disableClass => {
  5542. remove$2(component.element, disableClass);
  5543. });
  5544. const f = hasNative(component, disableConfig) ? nativeEnable : ariaEnable;
  5545. f(component);
  5546. disableConfig.onEnabled(component);
  5547. };
  5548. const isDisabled = (component, disableConfig) => hasNative(component, disableConfig) ? nativeIsDisabled(component) : ariaIsDisabled(component);
  5549. const set$4 = (component, disableConfig, disableState, disabled) => {
  5550. const f = disabled ? disable : enable;
  5551. f(component, disableConfig);
  5552. };
  5553. var DisableApis = /*#__PURE__*/Object.freeze({
  5554. __proto__: null,
  5555. enable: enable,
  5556. disable: disable,
  5557. isDisabled: isDisabled,
  5558. onLoad: onLoad$1,
  5559. set: set$4
  5560. });
  5561. const exhibit$5 = (base, disableConfig) => nu$7({ classes: disableConfig.disabled() ? disableConfig.disableClass.toArray() : [] });
  5562. const events$e = (disableConfig, disableState) => derive$2([
  5563. abort(execute$5(), (component, _simulatedEvent) => isDisabled(component, disableConfig)),
  5564. loadEvent(disableConfig, disableState, onLoad$1)
  5565. ]);
  5566. var ActiveDisable = /*#__PURE__*/Object.freeze({
  5567. __proto__: null,
  5568. exhibit: exhibit$5,
  5569. events: events$e
  5570. });
  5571. var DisableSchema = [
  5572. defaultedFunction('disabled', never),
  5573. defaulted('useNative', true),
  5574. option$3('disableClass'),
  5575. onHandler('onDisabled'),
  5576. onHandler('onEnabled')
  5577. ];
  5578. const Disabling = create$3({
  5579. fields: DisableSchema,
  5580. name: 'disabling',
  5581. active: ActiveDisable,
  5582. apis: DisableApis
  5583. });
  5584. const dehighlightAllExcept = (component, hConfig, hState, skip) => {
  5585. const highlighted = descendants(component.element, '.' + hConfig.highlightClass);
  5586. each$1(highlighted, h => {
  5587. if (!exists(skip, skipComp => skipComp.element === h)) {
  5588. remove$2(h, hConfig.highlightClass);
  5589. component.getSystem().getByDom(h).each(target => {
  5590. hConfig.onDehighlight(component, target);
  5591. emit(target, dehighlight$1());
  5592. });
  5593. }
  5594. });
  5595. };
  5596. const dehighlightAll = (component, hConfig, hState) => dehighlightAllExcept(component, hConfig, hState, []);
  5597. const dehighlight = (component, hConfig, hState, target) => {
  5598. if (isHighlighted(component, hConfig, hState, target)) {
  5599. remove$2(target.element, hConfig.highlightClass);
  5600. hConfig.onDehighlight(component, target);
  5601. emit(target, dehighlight$1());
  5602. }
  5603. };
  5604. const highlight = (component, hConfig, hState, target) => {
  5605. dehighlightAllExcept(component, hConfig, hState, [target]);
  5606. if (!isHighlighted(component, hConfig, hState, target)) {
  5607. add$2(target.element, hConfig.highlightClass);
  5608. hConfig.onHighlight(component, target);
  5609. emit(target, highlight$1());
  5610. }
  5611. };
  5612. const highlightFirst = (component, hConfig, hState) => {
  5613. getFirst(component, hConfig).each(firstComp => {
  5614. highlight(component, hConfig, hState, firstComp);
  5615. });
  5616. };
  5617. const highlightLast = (component, hConfig, hState) => {
  5618. getLast(component, hConfig).each(lastComp => {
  5619. highlight(component, hConfig, hState, lastComp);
  5620. });
  5621. };
  5622. const highlightAt = (component, hConfig, hState, index) => {
  5623. getByIndex(component, hConfig, hState, index).fold(err => {
  5624. throw err;
  5625. }, firstComp => {
  5626. highlight(component, hConfig, hState, firstComp);
  5627. });
  5628. };
  5629. const highlightBy = (component, hConfig, hState, predicate) => {
  5630. const candidates = getCandidates(component, hConfig);
  5631. const targetComp = find$5(candidates, predicate);
  5632. targetComp.each(c => {
  5633. highlight(component, hConfig, hState, c);
  5634. });
  5635. };
  5636. const isHighlighted = (component, hConfig, hState, queryTarget) => has(queryTarget.element, hConfig.highlightClass);
  5637. const getHighlighted = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.highlightClass).bind(e => component.getSystem().getByDom(e).toOptional());
  5638. const getByIndex = (component, hConfig, hState, index) => {
  5639. const items = descendants(component.element, '.' + hConfig.itemClass);
  5640. return Optional.from(items[index]).fold(() => Result.error(new Error('No element found with index ' + index)), component.getSystem().getByDom);
  5641. };
  5642. const getFirst = (component, hConfig, _hState) => descendant(component.element, '.' + hConfig.itemClass).bind(e => component.getSystem().getByDom(e).toOptional());
  5643. const getLast = (component, hConfig, _hState) => {
  5644. const items = descendants(component.element, '.' + hConfig.itemClass);
  5645. const last = items.length > 0 ? Optional.some(items[items.length - 1]) : Optional.none();
  5646. return last.bind(c => component.getSystem().getByDom(c).toOptional());
  5647. };
  5648. const getDelta$2 = (component, hConfig, hState, delta) => {
  5649. const items = descendants(component.element, '.' + hConfig.itemClass);
  5650. const current = findIndex$1(items, item => has(item, hConfig.highlightClass));
  5651. return current.bind(selected => {
  5652. const dest = cycleBy(selected, delta, 0, items.length - 1);
  5653. return component.getSystem().getByDom(items[dest]).toOptional();
  5654. });
  5655. };
  5656. const getPrevious = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, -1);
  5657. const getNext = (component, hConfig, hState) => getDelta$2(component, hConfig, hState, +1);
  5658. const getCandidates = (component, hConfig, _hState) => {
  5659. const items = descendants(component.element, '.' + hConfig.itemClass);
  5660. return cat(map$2(items, i => component.getSystem().getByDom(i).toOptional()));
  5661. };
  5662. var HighlightApis = /*#__PURE__*/Object.freeze({
  5663. __proto__: null,
  5664. dehighlightAll: dehighlightAll,
  5665. dehighlight: dehighlight,
  5666. highlight: highlight,
  5667. highlightFirst: highlightFirst,
  5668. highlightLast: highlightLast,
  5669. highlightAt: highlightAt,
  5670. highlightBy: highlightBy,
  5671. isHighlighted: isHighlighted,
  5672. getHighlighted: getHighlighted,
  5673. getFirst: getFirst,
  5674. getLast: getLast,
  5675. getPrevious: getPrevious,
  5676. getNext: getNext,
  5677. getCandidates: getCandidates
  5678. });
  5679. var HighlightSchema = [
  5680. required$1('highlightClass'),
  5681. required$1('itemClass'),
  5682. onHandler('onHighlight'),
  5683. onHandler('onDehighlight')
  5684. ];
  5685. const Highlighting = create$3({
  5686. fields: HighlightSchema,
  5687. name: 'highlighting',
  5688. apis: HighlightApis
  5689. });
  5690. const BACKSPACE = [8];
  5691. const TAB = [9];
  5692. const ENTER = [13];
  5693. const ESCAPE = [27];
  5694. const SPACE = [32];
  5695. const LEFT = [37];
  5696. const UP = [38];
  5697. const RIGHT = [39];
  5698. const DOWN = [40];
  5699. const cyclePrev = (values, index, predicate) => {
  5700. const before = reverse(values.slice(0, index));
  5701. const after = reverse(values.slice(index + 1));
  5702. return find$5(before.concat(after), predicate);
  5703. };
  5704. const tryPrev = (values, index, predicate) => {
  5705. const before = reverse(values.slice(0, index));
  5706. return find$5(before, predicate);
  5707. };
  5708. const cycleNext = (values, index, predicate) => {
  5709. const before = values.slice(0, index);
  5710. const after = values.slice(index + 1);
  5711. return find$5(after.concat(before), predicate);
  5712. };
  5713. const tryNext = (values, index, predicate) => {
  5714. const after = values.slice(index + 1);
  5715. return find$5(after, predicate);
  5716. };
  5717. const inSet = keys => event => {
  5718. const raw = event.raw;
  5719. return contains$2(keys, raw.which);
  5720. };
  5721. const and = preds => event => forall(preds, pred => pred(event));
  5722. const isShift = event => {
  5723. const raw = event.raw;
  5724. return raw.shiftKey === true;
  5725. };
  5726. const isControl = event => {
  5727. const raw = event.raw;
  5728. return raw.ctrlKey === true;
  5729. };
  5730. const isNotShift = not(isShift);
  5731. const rule = (matches, action) => ({
  5732. matches,
  5733. classification: action
  5734. });
  5735. const choose = (transitions, event) => {
  5736. const transition = find$5(transitions, t => t.matches(event));
  5737. return transition.map(t => t.classification);
  5738. };
  5739. const reportFocusShifting = (component, prevFocus, newFocus) => {
  5740. const noChange = prevFocus.exists(p => newFocus.exists(n => eq(n, p)));
  5741. if (!noChange) {
  5742. emitWith(component, focusShifted(), {
  5743. prevFocus,
  5744. newFocus
  5745. });
  5746. }
  5747. };
  5748. const dom$2 = () => {
  5749. const get = component => search(component.element);
  5750. const set = (component, focusee) => {
  5751. const prevFocus = get(component);
  5752. component.getSystem().triggerFocus(focusee, component.element);
  5753. const newFocus = get(component);
  5754. reportFocusShifting(component, prevFocus, newFocus);
  5755. };
  5756. return {
  5757. get,
  5758. set
  5759. };
  5760. };
  5761. const highlights = () => {
  5762. const get = component => Highlighting.getHighlighted(component).map(item => item.element);
  5763. const set = (component, element) => {
  5764. const prevFocus = get(component);
  5765. component.getSystem().getByDom(element).fold(noop, item => {
  5766. Highlighting.highlight(component, item);
  5767. });
  5768. const newFocus = get(component);
  5769. reportFocusShifting(component, prevFocus, newFocus);
  5770. };
  5771. return {
  5772. get,
  5773. set
  5774. };
  5775. };
  5776. var FocusInsideModes;
  5777. (function (FocusInsideModes) {
  5778. FocusInsideModes['OnFocusMode'] = 'onFocus';
  5779. FocusInsideModes['OnEnterOrSpaceMode'] = 'onEnterOrSpace';
  5780. FocusInsideModes['OnApiMode'] = 'onApi';
  5781. }(FocusInsideModes || (FocusInsideModes = {})));
  5782. const typical = (infoSchema, stateInit, getKeydownRules, getKeyupRules, optFocusIn) => {
  5783. const schema = () => infoSchema.concat([
  5784. defaulted('focusManager', dom$2()),
  5785. defaultedOf('focusInside', 'onFocus', valueOf(val => contains$2([
  5786. 'onFocus',
  5787. 'onEnterOrSpace',
  5788. 'onApi'
  5789. ], val) ? Result.value(val) : Result.error('Invalid value for focusInside'))),
  5790. output$1('handler', me),
  5791. output$1('state', stateInit),
  5792. output$1('sendFocusIn', optFocusIn)
  5793. ]);
  5794. const processKey = (component, simulatedEvent, getRules, keyingConfig, keyingState) => {
  5795. const rules = getRules(component, simulatedEvent, keyingConfig, keyingState);
  5796. return choose(rules, simulatedEvent.event).bind(rule => rule(component, simulatedEvent, keyingConfig, keyingState));
  5797. };
  5798. const toEvents = (keyingConfig, keyingState) => {
  5799. const onFocusHandler = keyingConfig.focusInside !== FocusInsideModes.OnFocusMode ? Optional.none() : optFocusIn(keyingConfig).map(focusIn => run$1(focus$4(), (component, simulatedEvent) => {
  5800. focusIn(component, keyingConfig, keyingState);
  5801. simulatedEvent.stop();
  5802. }));
  5803. const tryGoInsideComponent = (component, simulatedEvent) => {
  5804. const isEnterOrSpace = inSet(SPACE.concat(ENTER))(simulatedEvent.event);
  5805. if (keyingConfig.focusInside === FocusInsideModes.OnEnterOrSpaceMode && isEnterOrSpace && isSource(component, simulatedEvent)) {
  5806. optFocusIn(keyingConfig).each(focusIn => {
  5807. focusIn(component, keyingConfig, keyingState);
  5808. simulatedEvent.stop();
  5809. });
  5810. }
  5811. };
  5812. const keyboardEvents = [
  5813. run$1(keydown(), (component, simulatedEvent) => {
  5814. processKey(component, simulatedEvent, getKeydownRules, keyingConfig, keyingState).fold(() => {
  5815. tryGoInsideComponent(component, simulatedEvent);
  5816. }, _ => {
  5817. simulatedEvent.stop();
  5818. });
  5819. }),
  5820. run$1(keyup(), (component, simulatedEvent) => {
  5821. processKey(component, simulatedEvent, getKeyupRules, keyingConfig, keyingState).each(_ => {
  5822. simulatedEvent.stop();
  5823. });
  5824. })
  5825. ];
  5826. return derive$2(onFocusHandler.toArray().concat(keyboardEvents));
  5827. };
  5828. const me = {
  5829. schema,
  5830. processKey,
  5831. toEvents
  5832. };
  5833. return me;
  5834. };
  5835. const create$1 = cyclicField => {
  5836. const schema = [
  5837. option$3('onEscape'),
  5838. option$3('onEnter'),
  5839. defaulted('selector', '[data-alloy-tabstop="true"]:not(:disabled)'),
  5840. defaulted('firstTabstop', 0),
  5841. defaulted('useTabstopAt', always),
  5842. option$3('visibilitySelector')
  5843. ].concat([cyclicField]);
  5844. const isVisible = (tabbingConfig, element) => {
  5845. const target = tabbingConfig.visibilitySelector.bind(sel => closest$1(element, sel)).getOr(element);
  5846. return get$d(target) > 0;
  5847. };
  5848. const findInitial = (component, tabbingConfig) => {
  5849. const tabstops = descendants(component.element, tabbingConfig.selector);
  5850. const visibles = filter$2(tabstops, elem => isVisible(tabbingConfig, elem));
  5851. return Optional.from(visibles[tabbingConfig.firstTabstop]);
  5852. };
  5853. const findCurrent = (component, tabbingConfig) => tabbingConfig.focusManager.get(component).bind(elem => closest$1(elem, tabbingConfig.selector));
  5854. const isTabstop = (tabbingConfig, element) => isVisible(tabbingConfig, element) && tabbingConfig.useTabstopAt(element);
  5855. const focusIn = (component, tabbingConfig, _tabbingState) => {
  5856. findInitial(component, tabbingConfig).each(target => {
  5857. tabbingConfig.focusManager.set(component, target);
  5858. });
  5859. };
  5860. const goFromTabstop = (component, tabstops, stopIndex, tabbingConfig, cycle) => cycle(tabstops, stopIndex, elem => isTabstop(tabbingConfig, elem)).fold(() => tabbingConfig.cyclic ? Optional.some(true) : Optional.none(), target => {
  5861. tabbingConfig.focusManager.set(component, target);
  5862. return Optional.some(true);
  5863. });
  5864. const go = (component, _simulatedEvent, tabbingConfig, cycle) => {
  5865. const tabstops = descendants(component.element, tabbingConfig.selector);
  5866. return findCurrent(component, tabbingConfig).bind(tabstop => {
  5867. const optStopIndex = findIndex$1(tabstops, curry(eq, tabstop));
  5868. return optStopIndex.bind(stopIndex => goFromTabstop(component, tabstops, stopIndex, tabbingConfig, cycle));
  5869. });
  5870. };
  5871. const goBackwards = (component, simulatedEvent, tabbingConfig) => {
  5872. const navigate = tabbingConfig.cyclic ? cyclePrev : tryPrev;
  5873. return go(component, simulatedEvent, tabbingConfig, navigate);
  5874. };
  5875. const goForwards = (component, simulatedEvent, tabbingConfig) => {
  5876. const navigate = tabbingConfig.cyclic ? cycleNext : tryNext;
  5877. return go(component, simulatedEvent, tabbingConfig, navigate);
  5878. };
  5879. const execute = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEnter.bind(f => f(component, simulatedEvent));
  5880. const exit = (component, simulatedEvent, tabbingConfig) => tabbingConfig.onEscape.bind(f => f(component, simulatedEvent));
  5881. const getKeydownRules = constant$1([
  5882. rule(and([
  5883. isShift,
  5884. inSet(TAB)
  5885. ]), goBackwards),
  5886. rule(inSet(TAB), goForwards),
  5887. rule(and([
  5888. isNotShift,
  5889. inSet(ENTER)
  5890. ]), execute)
  5891. ]);
  5892. const getKeyupRules = constant$1([rule(inSet(ESCAPE), exit)]);
  5893. return typical(schema, NoState.init, getKeydownRules, getKeyupRules, () => Optional.some(focusIn));
  5894. };
  5895. var AcyclicType = create$1(customField('cyclic', never));
  5896. var CyclicType = create$1(customField('cyclic', always));
  5897. const doDefaultExecute = (component, _simulatedEvent, focused) => {
  5898. dispatch(component, focused, execute$5());
  5899. return Optional.some(true);
  5900. };
  5901. const defaultExecute = (component, simulatedEvent, focused) => {
  5902. const isComplex = inside(focused) && inSet(SPACE)(simulatedEvent.event);
  5903. return isComplex ? Optional.none() : doDefaultExecute(component, simulatedEvent, focused);
  5904. };
  5905. const stopEventForFirefox = (_component, _simulatedEvent) => Optional.some(true);
  5906. const schema$v = [
  5907. defaulted('execute', defaultExecute),
  5908. defaulted('useSpace', false),
  5909. defaulted('useEnter', true),
  5910. defaulted('useControlEnter', false),
  5911. defaulted('useDown', false)
  5912. ];
  5913. const execute$4 = (component, simulatedEvent, executeConfig) => executeConfig.execute(component, simulatedEvent, component.element);
  5914. const getKeydownRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => {
  5915. const spaceExec = executeConfig.useSpace && !inside(component.element) ? SPACE : [];
  5916. const enterExec = executeConfig.useEnter ? ENTER : [];
  5917. const downExec = executeConfig.useDown ? DOWN : [];
  5918. const execKeys = spaceExec.concat(enterExec).concat(downExec);
  5919. return [rule(inSet(execKeys), execute$4)].concat(executeConfig.useControlEnter ? [rule(and([
  5920. isControl,
  5921. inSet(ENTER)
  5922. ]), execute$4)] : []);
  5923. };
  5924. const getKeyupRules$5 = (component, _simulatedEvent, executeConfig, _executeState) => executeConfig.useSpace && !inside(component.element) ? [rule(inSet(SPACE), stopEventForFirefox)] : [];
  5925. var ExecutionType = typical(schema$v, NoState.init, getKeydownRules$5, getKeyupRules$5, () => Optional.none());
  5926. const flatgrid$1 = () => {
  5927. const dimensions = value$2();
  5928. const setGridSize = (numRows, numColumns) => {
  5929. dimensions.set({
  5930. numRows,
  5931. numColumns
  5932. });
  5933. };
  5934. const getNumRows = () => dimensions.get().map(d => d.numRows);
  5935. const getNumColumns = () => dimensions.get().map(d => d.numColumns);
  5936. return nu$8({
  5937. readState: () => dimensions.get().map(d => ({
  5938. numRows: String(d.numRows),
  5939. numColumns: String(d.numColumns)
  5940. })).getOr({
  5941. numRows: '?',
  5942. numColumns: '?'
  5943. }),
  5944. setGridSize,
  5945. getNumRows,
  5946. getNumColumns
  5947. });
  5948. };
  5949. const init$d = spec => spec.state(spec);
  5950. var KeyingState = /*#__PURE__*/Object.freeze({
  5951. __proto__: null,
  5952. flatgrid: flatgrid$1,
  5953. init: init$d
  5954. });
  5955. const useH = movement => (component, simulatedEvent, config, state) => {
  5956. const move = movement(component.element);
  5957. return use(move, component, simulatedEvent, config, state);
  5958. };
  5959. const west$1 = (moveLeft, moveRight) => {
  5960. const movement = onDirection(moveLeft, moveRight);
  5961. return useH(movement);
  5962. };
  5963. const east$1 = (moveLeft, moveRight) => {
  5964. const movement = onDirection(moveRight, moveLeft);
  5965. return useH(movement);
  5966. };
  5967. const useV = move => (component, simulatedEvent, config, state) => use(move, component, simulatedEvent, config, state);
  5968. const use = (move, component, simulatedEvent, config, state) => {
  5969. const outcome = config.focusManager.get(component).bind(focused => move(component.element, focused, config, state));
  5970. return outcome.map(newFocus => {
  5971. config.focusManager.set(component, newFocus);
  5972. return true;
  5973. });
  5974. };
  5975. const north$1 = useV;
  5976. const south$1 = useV;
  5977. const move$1 = useV;
  5978. const isHidden$1 = dom => dom.offsetWidth <= 0 && dom.offsetHeight <= 0;
  5979. const isVisible = element => !isHidden$1(element.dom);
  5980. const locate = (candidates, predicate) => findIndex$1(candidates, predicate).map(index => ({
  5981. index,
  5982. candidates
  5983. }));
  5984. const locateVisible = (container, current, selector) => {
  5985. const predicate = x => eq(x, current);
  5986. const candidates = descendants(container, selector);
  5987. const visible = filter$2(candidates, isVisible);
  5988. return locate(visible, predicate);
  5989. };
  5990. const findIndex = (elements, target) => findIndex$1(elements, elem => eq(target, elem));
  5991. const withGrid = (values, index, numCols, f) => {
  5992. const oldRow = Math.floor(index / numCols);
  5993. const oldColumn = index % numCols;
  5994. return f(oldRow, oldColumn).bind(address => {
  5995. const newIndex = address.row * numCols + address.column;
  5996. return newIndex >= 0 && newIndex < values.length ? Optional.some(values[newIndex]) : Optional.none();
  5997. });
  5998. };
  5999. const cycleHorizontal$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
  6000. const onLastRow = oldRow === numRows - 1;
  6001. const colsInRow = onLastRow ? values.length - oldRow * numCols : numCols;
  6002. const newColumn = cycleBy(oldColumn, delta, 0, colsInRow - 1);
  6003. return Optional.some({
  6004. row: oldRow,
  6005. column: newColumn
  6006. });
  6007. });
  6008. const cycleVertical$1 = (values, index, numRows, numCols, delta) => withGrid(values, index, numCols, (oldRow, oldColumn) => {
  6009. const newRow = cycleBy(oldRow, delta, 0, numRows - 1);
  6010. const onLastRow = newRow === numRows - 1;
  6011. const colsInRow = onLastRow ? values.length - newRow * numCols : numCols;
  6012. const newCol = clamp(oldColumn, 0, colsInRow - 1);
  6013. return Optional.some({
  6014. row: newRow,
  6015. column: newCol
  6016. });
  6017. });
  6018. const cycleRight$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, +1);
  6019. const cycleLeft$1 = (values, index, numRows, numCols) => cycleHorizontal$1(values, index, numRows, numCols, -1);
  6020. const cycleUp$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, -1);
  6021. const cycleDown$1 = (values, index, numRows, numCols) => cycleVertical$1(values, index, numRows, numCols, +1);
  6022. const schema$u = [
  6023. required$1('selector'),
  6024. defaulted('execute', defaultExecute),
  6025. onKeyboardHandler('onEscape'),
  6026. defaulted('captureTab', false),
  6027. initSize()
  6028. ];
  6029. const focusIn$3 = (component, gridConfig, _gridState) => {
  6030. descendant(component.element, gridConfig.selector).each(first => {
  6031. gridConfig.focusManager.set(component, first);
  6032. });
  6033. };
  6034. const findCurrent$1 = (component, gridConfig) => gridConfig.focusManager.get(component).bind(elem => closest$1(elem, gridConfig.selector));
  6035. const execute$3 = (component, simulatedEvent, gridConfig, _gridState) => findCurrent$1(component, gridConfig).bind(focused => gridConfig.execute(component, simulatedEvent, focused));
  6036. 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)));
  6037. const handleTab = (_component, _simulatedEvent, gridConfig) => gridConfig.captureTab ? Optional.some(true) : Optional.none();
  6038. const doEscape$1 = (component, simulatedEvent, gridConfig) => gridConfig.onEscape(component, simulatedEvent);
  6039. const moveLeft$3 = doMove$2(cycleLeft$1);
  6040. const moveRight$3 = doMove$2(cycleRight$1);
  6041. const moveNorth$1 = doMove$2(cycleUp$1);
  6042. const moveSouth$1 = doMove$2(cycleDown$1);
  6043. const getKeydownRules$4 = constant$1([
  6044. rule(inSet(LEFT), west$1(moveLeft$3, moveRight$3)),
  6045. rule(inSet(RIGHT), east$1(moveLeft$3, moveRight$3)),
  6046. rule(inSet(UP), north$1(moveNorth$1)),
  6047. rule(inSet(DOWN), south$1(moveSouth$1)),
  6048. rule(and([
  6049. isShift,
  6050. inSet(TAB)
  6051. ]), handleTab),
  6052. rule(and([
  6053. isNotShift,
  6054. inSet(TAB)
  6055. ]), handleTab),
  6056. rule(inSet(SPACE.concat(ENTER)), execute$3)
  6057. ]);
  6058. const getKeyupRules$4 = constant$1([
  6059. rule(inSet(ESCAPE), doEscape$1),
  6060. rule(inSet(SPACE), stopEventForFirefox)
  6061. ]);
  6062. var FlatgridType = typical(schema$u, flatgrid$1, getKeydownRules$4, getKeyupRules$4, () => Optional.some(focusIn$3));
  6063. const horizontal = (container, selector, current, delta) => {
  6064. const isDisabledButton = candidate => name$3(candidate) === 'button' && get$f(candidate, 'disabled') === 'disabled';
  6065. const tryCycle = (initial, index, candidates) => {
  6066. const newIndex = cycleBy(index, delta, 0, candidates.length - 1);
  6067. if (newIndex === initial) {
  6068. return Optional.none();
  6069. } else {
  6070. return isDisabledButton(candidates[newIndex]) ? tryCycle(initial, newIndex, candidates) : Optional.from(candidates[newIndex]);
  6071. }
  6072. };
  6073. return locateVisible(container, current, selector).bind(identified => {
  6074. const index = identified.index;
  6075. const candidates = identified.candidates;
  6076. return tryCycle(index, index, candidates);
  6077. });
  6078. };
  6079. const schema$t = [
  6080. required$1('selector'),
  6081. defaulted('getInitial', Optional.none),
  6082. defaulted('execute', defaultExecute),
  6083. onKeyboardHandler('onEscape'),
  6084. defaulted('executeOnMove', false),
  6085. defaulted('allowVertical', true)
  6086. ];
  6087. const findCurrent = (component, flowConfig) => flowConfig.focusManager.get(component).bind(elem => closest$1(elem, flowConfig.selector));
  6088. const execute$2 = (component, simulatedEvent, flowConfig) => findCurrent(component, flowConfig).bind(focused => flowConfig.execute(component, simulatedEvent, focused));
  6089. const focusIn$2 = (component, flowConfig, _state) => {
  6090. flowConfig.getInitial(component).orThunk(() => descendant(component.element, flowConfig.selector)).each(first => {
  6091. flowConfig.focusManager.set(component, first);
  6092. });
  6093. };
  6094. const moveLeft$2 = (element, focused, info) => horizontal(element, info.selector, focused, -1);
  6095. const moveRight$2 = (element, focused, info) => horizontal(element, info.selector, focused, +1);
  6096. const doMove$1 = movement => (component, simulatedEvent, flowConfig, flowState) => movement(component, simulatedEvent, flowConfig, flowState).bind(() => flowConfig.executeOnMove ? execute$2(component, simulatedEvent, flowConfig) : Optional.some(true));
  6097. const doEscape = (component, simulatedEvent, flowConfig) => flowConfig.onEscape(component, simulatedEvent);
  6098. const getKeydownRules$3 = (_component, _se, flowConfig, _flowState) => {
  6099. const westMovers = LEFT.concat(flowConfig.allowVertical ? UP : []);
  6100. const eastMovers = RIGHT.concat(flowConfig.allowVertical ? DOWN : []);
  6101. return [
  6102. rule(inSet(westMovers), doMove$1(west$1(moveLeft$2, moveRight$2))),
  6103. rule(inSet(eastMovers), doMove$1(east$1(moveLeft$2, moveRight$2))),
  6104. rule(inSet(ENTER), execute$2),
  6105. rule(inSet(SPACE), execute$2)
  6106. ];
  6107. };
  6108. const getKeyupRules$3 = constant$1([
  6109. rule(inSet(SPACE), stopEventForFirefox),
  6110. rule(inSet(ESCAPE), doEscape)
  6111. ]);
  6112. var FlowType = typical(schema$t, NoState.init, getKeydownRules$3, getKeyupRules$3, () => Optional.some(focusIn$2));
  6113. const toCell = (matrix, rowIndex, columnIndex) => Optional.from(matrix[rowIndex]).bind(row => Optional.from(row[columnIndex]).map(cell => ({
  6114. rowIndex,
  6115. columnIndex,
  6116. cell
  6117. })));
  6118. const cycleHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
  6119. const row = matrix[rowIndex];
  6120. const colsInRow = row.length;
  6121. const newColIndex = cycleBy(startCol, deltaCol, 0, colsInRow - 1);
  6122. return toCell(matrix, rowIndex, newColIndex);
  6123. };
  6124. const cycleVertical = (matrix, colIndex, startRow, deltaRow) => {
  6125. const nextRowIndex = cycleBy(startRow, deltaRow, 0, matrix.length - 1);
  6126. const colsInNextRow = matrix[nextRowIndex].length;
  6127. const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
  6128. return toCell(matrix, nextRowIndex, nextColIndex);
  6129. };
  6130. const moveHorizontal = (matrix, rowIndex, startCol, deltaCol) => {
  6131. const row = matrix[rowIndex];
  6132. const colsInRow = row.length;
  6133. const newColIndex = clamp(startCol + deltaCol, 0, colsInRow - 1);
  6134. return toCell(matrix, rowIndex, newColIndex);
  6135. };
  6136. const moveVertical = (matrix, colIndex, startRow, deltaRow) => {
  6137. const nextRowIndex = clamp(startRow + deltaRow, 0, matrix.length - 1);
  6138. const colsInNextRow = matrix[nextRowIndex].length;
  6139. const nextColIndex = clamp(colIndex, 0, colsInNextRow - 1);
  6140. return toCell(matrix, nextRowIndex, nextColIndex);
  6141. };
  6142. const cycleRight = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, +1);
  6143. const cycleLeft = (matrix, startRow, startCol) => cycleHorizontal(matrix, startRow, startCol, -1);
  6144. const cycleUp = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, -1);
  6145. const cycleDown = (matrix, startRow, startCol) => cycleVertical(matrix, startCol, startRow, +1);
  6146. const moveLeft$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, -1);
  6147. const moveRight$1 = (matrix, startRow, startCol) => moveHorizontal(matrix, startRow, startCol, +1);
  6148. const moveUp$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, -1);
  6149. const moveDown$1 = (matrix, startRow, startCol) => moveVertical(matrix, startCol, startRow, +1);
  6150. const schema$s = [
  6151. requiredObjOf('selectors', [
  6152. required$1('row'),
  6153. required$1('cell')
  6154. ]),
  6155. defaulted('cycles', true),
  6156. defaulted('previousSelector', Optional.none),
  6157. defaulted('execute', defaultExecute)
  6158. ];
  6159. const focusIn$1 = (component, matrixConfig, _state) => {
  6160. const focused = matrixConfig.previousSelector(component).orThunk(() => {
  6161. const selectors = matrixConfig.selectors;
  6162. return descendant(component.element, selectors.cell);
  6163. });
  6164. focused.each(cell => {
  6165. matrixConfig.focusManager.set(component, cell);
  6166. });
  6167. };
  6168. const execute$1 = (component, simulatedEvent, matrixConfig) => search(component.element).bind(focused => matrixConfig.execute(component, simulatedEvent, focused));
  6169. const toMatrix = (rows, matrixConfig) => map$2(rows, row => descendants(row, matrixConfig.selectors.cell));
  6170. const doMove = (ifCycle, ifMove) => (element, focused, matrixConfig) => {
  6171. const move = matrixConfig.cycles ? ifCycle : ifMove;
  6172. return closest$1(focused, matrixConfig.selectors.row).bind(inRow => {
  6173. const cellsInRow = descendants(inRow, matrixConfig.selectors.cell);
  6174. return findIndex(cellsInRow, focused).bind(colIndex => {
  6175. const allRows = descendants(element, matrixConfig.selectors.row);
  6176. return findIndex(allRows, inRow).bind(rowIndex => {
  6177. const matrix = toMatrix(allRows, matrixConfig);
  6178. return move(matrix, rowIndex, colIndex).map(next => next.cell);
  6179. });
  6180. });
  6181. });
  6182. };
  6183. const moveLeft = doMove(cycleLeft, moveLeft$1);
  6184. const moveRight = doMove(cycleRight, moveRight$1);
  6185. const moveNorth = doMove(cycleUp, moveUp$1);
  6186. const moveSouth = doMove(cycleDown, moveDown$1);
  6187. const getKeydownRules$2 = constant$1([
  6188. rule(inSet(LEFT), west$1(moveLeft, moveRight)),
  6189. rule(inSet(RIGHT), east$1(moveLeft, moveRight)),
  6190. rule(inSet(UP), north$1(moveNorth)),
  6191. rule(inSet(DOWN), south$1(moveSouth)),
  6192. rule(inSet(SPACE.concat(ENTER)), execute$1)
  6193. ]);
  6194. const getKeyupRules$2 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  6195. var MatrixType = typical(schema$s, NoState.init, getKeydownRules$2, getKeyupRules$2, () => Optional.some(focusIn$1));
  6196. const schema$r = [
  6197. required$1('selector'),
  6198. defaulted('execute', defaultExecute),
  6199. defaulted('moveOnTab', false)
  6200. ];
  6201. const execute = (component, simulatedEvent, menuConfig) => menuConfig.focusManager.get(component).bind(focused => menuConfig.execute(component, simulatedEvent, focused));
  6202. const focusIn = (component, menuConfig, _state) => {
  6203. descendant(component.element, menuConfig.selector).each(first => {
  6204. menuConfig.focusManager.set(component, first);
  6205. });
  6206. };
  6207. const moveUp = (element, focused, info) => horizontal(element, info.selector, focused, -1);
  6208. const moveDown = (element, focused, info) => horizontal(element, info.selector, focused, +1);
  6209. const fireShiftTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveUp)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  6210. const fireTab = (component, simulatedEvent, menuConfig, menuState) => menuConfig.moveOnTab ? move$1(moveDown)(component, simulatedEvent, menuConfig, menuState) : Optional.none();
  6211. const getKeydownRules$1 = constant$1([
  6212. rule(inSet(UP), move$1(moveUp)),
  6213. rule(inSet(DOWN), move$1(moveDown)),
  6214. rule(and([
  6215. isShift,
  6216. inSet(TAB)
  6217. ]), fireShiftTab),
  6218. rule(and([
  6219. isNotShift,
  6220. inSet(TAB)
  6221. ]), fireTab),
  6222. rule(inSet(ENTER), execute),
  6223. rule(inSet(SPACE), execute)
  6224. ]);
  6225. const getKeyupRules$1 = constant$1([rule(inSet(SPACE), stopEventForFirefox)]);
  6226. var MenuType = typical(schema$r, NoState.init, getKeydownRules$1, getKeyupRules$1, () => Optional.some(focusIn));
  6227. const schema$q = [
  6228. onKeyboardHandler('onSpace'),
  6229. onKeyboardHandler('onEnter'),
  6230. onKeyboardHandler('onShiftEnter'),
  6231. onKeyboardHandler('onLeft'),
  6232. onKeyboardHandler('onRight'),
  6233. onKeyboardHandler('onTab'),
  6234. onKeyboardHandler('onShiftTab'),
  6235. onKeyboardHandler('onUp'),
  6236. onKeyboardHandler('onDown'),
  6237. onKeyboardHandler('onEscape'),
  6238. defaulted('stopSpaceKeyup', false),
  6239. option$3('focusIn')
  6240. ];
  6241. const getKeydownRules = (component, simulatedEvent, specialInfo) => [
  6242. rule(inSet(SPACE), specialInfo.onSpace),
  6243. rule(and([
  6244. isNotShift,
  6245. inSet(ENTER)
  6246. ]), specialInfo.onEnter),
  6247. rule(and([
  6248. isShift,
  6249. inSet(ENTER)
  6250. ]), specialInfo.onShiftEnter),
  6251. rule(and([
  6252. isShift,
  6253. inSet(TAB)
  6254. ]), specialInfo.onShiftTab),
  6255. rule(and([
  6256. isNotShift,
  6257. inSet(TAB)
  6258. ]), specialInfo.onTab),
  6259. rule(inSet(UP), specialInfo.onUp),
  6260. rule(inSet(DOWN), specialInfo.onDown),
  6261. rule(inSet(LEFT), specialInfo.onLeft),
  6262. rule(inSet(RIGHT), specialInfo.onRight),
  6263. rule(inSet(SPACE), specialInfo.onSpace)
  6264. ];
  6265. const getKeyupRules = (component, simulatedEvent, specialInfo) => [
  6266. ...specialInfo.stopSpaceKeyup ? [rule(inSet(SPACE), stopEventForFirefox)] : [],
  6267. rule(inSet(ESCAPE), specialInfo.onEscape)
  6268. ];
  6269. var SpecialType = typical(schema$q, NoState.init, getKeydownRules, getKeyupRules, specialInfo => specialInfo.focusIn);
  6270. const acyclic = AcyclicType.schema();
  6271. const cyclic = CyclicType.schema();
  6272. const flow = FlowType.schema();
  6273. const flatgrid = FlatgridType.schema();
  6274. const matrix = MatrixType.schema();
  6275. const execution = ExecutionType.schema();
  6276. const menu = MenuType.schema();
  6277. const special = SpecialType.schema();
  6278. var KeyboardBranches = /*#__PURE__*/Object.freeze({
  6279. __proto__: null,
  6280. acyclic: acyclic,
  6281. cyclic: cyclic,
  6282. flow: flow,
  6283. flatgrid: flatgrid,
  6284. matrix: matrix,
  6285. execution: execution,
  6286. menu: menu,
  6287. special: special
  6288. });
  6289. const isFlatgridState = keyState => hasNonNullableKey(keyState, 'setGridSize');
  6290. const Keying = createModes({
  6291. branchKey: 'mode',
  6292. branches: KeyboardBranches,
  6293. name: 'keying',
  6294. active: {
  6295. events: (keyingConfig, keyingState) => {
  6296. const handler = keyingConfig.handler;
  6297. return handler.toEvents(keyingConfig, keyingState);
  6298. }
  6299. },
  6300. apis: {
  6301. focusIn: (component, keyConfig, keyState) => {
  6302. keyConfig.sendFocusIn(keyConfig).fold(() => {
  6303. component.getSystem().triggerFocus(component.element, component.element);
  6304. }, sendFocusIn => {
  6305. sendFocusIn(component, keyConfig, keyState);
  6306. });
  6307. },
  6308. setGridSize: (component, keyConfig, keyState, numRows, numColumns) => {
  6309. if (!isFlatgridState(keyState)) {
  6310. console.error('Layout does not support setGridSize');
  6311. } else {
  6312. keyState.setGridSize(numRows, numColumns);
  6313. }
  6314. }
  6315. },
  6316. state: KeyingState
  6317. });
  6318. const withoutReuse = (parent, data) => {
  6319. preserve$1(() => {
  6320. replaceChildren(parent, data, () => map$2(data, parent.getSystem().build));
  6321. }, parent.element);
  6322. };
  6323. const withReuse = (parent, data) => {
  6324. preserve$1(() => {
  6325. virtualReplaceChildren(parent, data, () => {
  6326. return patchSpecChildren(parent.element, data, parent.getSystem().buildOrPatch);
  6327. });
  6328. }, parent.element);
  6329. };
  6330. const virtualReplace = (component, replacee, replaceeIndex, childSpec) => {
  6331. virtualDetach(replacee);
  6332. const child = patchSpecChild(component.element, replaceeIndex, childSpec, component.getSystem().buildOrPatch);
  6333. virtualAttach(component, child);
  6334. component.syncComponents();
  6335. };
  6336. const insert = (component, insertion, childSpec) => {
  6337. const child = component.getSystem().build(childSpec);
  6338. attachWith(component, child, insertion);
  6339. };
  6340. const replace = (component, replacee, replaceeIndex, childSpec) => {
  6341. detach(replacee);
  6342. insert(component, (p, c) => appendAt(p, c, replaceeIndex), childSpec);
  6343. };
  6344. const set$3 = (component, replaceConfig, replaceState, data) => {
  6345. const replacer = replaceConfig.reuseDom ? withReuse : withoutReuse;
  6346. return replacer(component, data);
  6347. };
  6348. const append = (component, replaceConfig, replaceState, appendee) => {
  6349. insert(component, append$2, appendee);
  6350. };
  6351. const prepend = (component, replaceConfig, replaceState, prependee) => {
  6352. insert(component, prepend$1, prependee);
  6353. };
  6354. const remove = (component, replaceConfig, replaceState, removee) => {
  6355. const children = contents(component);
  6356. const foundChild = find$5(children, child => eq(removee.element, child.element));
  6357. foundChild.each(detach);
  6358. };
  6359. const contents = (component, _replaceConfig) => component.components();
  6360. const replaceAt = (component, replaceConfig, replaceState, replaceeIndex, replacer) => {
  6361. const children = contents(component);
  6362. return Optional.from(children[replaceeIndex]).map(replacee => {
  6363. replacer.fold(() => detach(replacee), r => {
  6364. const replacer = replaceConfig.reuseDom ? virtualReplace : replace;
  6365. replacer(component, replacee, replaceeIndex, r);
  6366. });
  6367. return replacee;
  6368. });
  6369. };
  6370. const replaceBy = (component, replaceConfig, replaceState, replaceePred, replacer) => {
  6371. const children = contents(component);
  6372. return findIndex$1(children, replaceePred).bind(replaceeIndex => replaceAt(component, replaceConfig, replaceState, replaceeIndex, replacer));
  6373. };
  6374. var ReplaceApis = /*#__PURE__*/Object.freeze({
  6375. __proto__: null,
  6376. append: append,
  6377. prepend: prepend,
  6378. remove: remove,
  6379. replaceAt: replaceAt,
  6380. replaceBy: replaceBy,
  6381. set: set$3,
  6382. contents: contents
  6383. });
  6384. const Replacing = create$3({
  6385. fields: [defaultedBoolean('reuseDom', true)],
  6386. name: 'replacing',
  6387. apis: ReplaceApis
  6388. });
  6389. const events$d = (name, eventHandlers) => {
  6390. const events = derive$2(eventHandlers);
  6391. return create$3({
  6392. fields: [required$1('enabled')],
  6393. name,
  6394. active: { events: constant$1(events) }
  6395. });
  6396. };
  6397. const config = (name, eventHandlers) => {
  6398. const me = events$d(name, eventHandlers);
  6399. return {
  6400. key: name,
  6401. value: {
  6402. config: {},
  6403. me,
  6404. configAsRaw: constant$1({}),
  6405. initialConfig: {},
  6406. state: NoState
  6407. }
  6408. };
  6409. };
  6410. const focus$2 = (component, focusConfig) => {
  6411. if (!focusConfig.ignore) {
  6412. focus$3(component.element);
  6413. focusConfig.onFocus(component);
  6414. }
  6415. };
  6416. const blur = (component, focusConfig) => {
  6417. if (!focusConfig.ignore) {
  6418. blur$1(component.element);
  6419. }
  6420. };
  6421. const isFocused = component => hasFocus(component.element);
  6422. var FocusApis = /*#__PURE__*/Object.freeze({
  6423. __proto__: null,
  6424. focus: focus$2,
  6425. blur: blur,
  6426. isFocused: isFocused
  6427. });
  6428. const exhibit$4 = (base, focusConfig) => {
  6429. const mod = focusConfig.ignore ? {} : { attributes: { tabindex: '-1' } };
  6430. return nu$7(mod);
  6431. };
  6432. const events$c = focusConfig => derive$2([run$1(focus$4(), (component, simulatedEvent) => {
  6433. focus$2(component, focusConfig);
  6434. simulatedEvent.stop();
  6435. })].concat(focusConfig.stopMousedown ? [run$1(mousedown(), (_, simulatedEvent) => {
  6436. simulatedEvent.event.prevent();
  6437. })] : []));
  6438. var ActiveFocus = /*#__PURE__*/Object.freeze({
  6439. __proto__: null,
  6440. exhibit: exhibit$4,
  6441. events: events$c
  6442. });
  6443. var FocusSchema = [
  6444. onHandler('onFocus'),
  6445. defaulted('stopMousedown', false),
  6446. defaulted('ignore', false)
  6447. ];
  6448. const Focusing = create$3({
  6449. fields: FocusSchema,
  6450. name: 'focusing',
  6451. active: ActiveFocus,
  6452. apis: FocusApis
  6453. });
  6454. const SetupBehaviourCellState = initialState => {
  6455. const init = () => {
  6456. const cell = Cell(initialState);
  6457. const get = () => cell.get();
  6458. const set = newState => cell.set(newState);
  6459. const clear = () => cell.set(initialState);
  6460. const readState = () => cell.get();
  6461. return {
  6462. get,
  6463. set,
  6464. clear,
  6465. readState
  6466. };
  6467. };
  6468. return { init };
  6469. };
  6470. const updateAriaState = (component, toggleConfig, toggleState) => {
  6471. const ariaInfo = toggleConfig.aria;
  6472. ariaInfo.update(component, ariaInfo, toggleState.get());
  6473. };
  6474. const updateClass = (component, toggleConfig, toggleState) => {
  6475. toggleConfig.toggleClass.each(toggleClass => {
  6476. if (toggleState.get()) {
  6477. add$2(component.element, toggleClass);
  6478. } else {
  6479. remove$2(component.element, toggleClass);
  6480. }
  6481. });
  6482. };
  6483. const set$2 = (component, toggleConfig, toggleState, state) => {
  6484. const initialState = toggleState.get();
  6485. toggleState.set(state);
  6486. updateClass(component, toggleConfig, toggleState);
  6487. updateAriaState(component, toggleConfig, toggleState);
  6488. if (initialState !== state) {
  6489. toggleConfig.onToggled(component, state);
  6490. }
  6491. };
  6492. const toggle$2 = (component, toggleConfig, toggleState) => {
  6493. set$2(component, toggleConfig, toggleState, !toggleState.get());
  6494. };
  6495. const on = (component, toggleConfig, toggleState) => {
  6496. set$2(component, toggleConfig, toggleState, true);
  6497. };
  6498. const off = (component, toggleConfig, toggleState) => {
  6499. set$2(component, toggleConfig, toggleState, false);
  6500. };
  6501. const isOn = (component, toggleConfig, toggleState) => toggleState.get();
  6502. const onLoad = (component, toggleConfig, toggleState) => {
  6503. set$2(component, toggleConfig, toggleState, toggleConfig.selected);
  6504. };
  6505. var ToggleApis = /*#__PURE__*/Object.freeze({
  6506. __proto__: null,
  6507. onLoad: onLoad,
  6508. toggle: toggle$2,
  6509. isOn: isOn,
  6510. on: on,
  6511. off: off,
  6512. set: set$2
  6513. });
  6514. const exhibit$3 = () => nu$7({});
  6515. const events$b = (toggleConfig, toggleState) => {
  6516. const execute = executeEvent(toggleConfig, toggleState, toggle$2);
  6517. const load = loadEvent(toggleConfig, toggleState, onLoad);
  6518. return derive$2(flatten([
  6519. toggleConfig.toggleOnExecute ? [execute] : [],
  6520. [load]
  6521. ]));
  6522. };
  6523. var ActiveToggle = /*#__PURE__*/Object.freeze({
  6524. __proto__: null,
  6525. exhibit: exhibit$3,
  6526. events: events$b
  6527. });
  6528. const updatePressed = (component, ariaInfo, status) => {
  6529. set$9(component.element, 'aria-pressed', status);
  6530. if (ariaInfo.syncWithExpanded) {
  6531. updateExpanded(component, ariaInfo, status);
  6532. }
  6533. };
  6534. const updateSelected = (component, ariaInfo, status) => {
  6535. set$9(component.element, 'aria-selected', status);
  6536. };
  6537. const updateChecked = (component, ariaInfo, status) => {
  6538. set$9(component.element, 'aria-checked', status);
  6539. };
  6540. const updateExpanded = (component, ariaInfo, status) => {
  6541. set$9(component.element, 'aria-expanded', status);
  6542. };
  6543. var ToggleSchema = [
  6544. defaulted('selected', false),
  6545. option$3('toggleClass'),
  6546. defaulted('toggleOnExecute', true),
  6547. onHandler('onToggled'),
  6548. defaultedOf('aria', { mode: 'none' }, choose$1('mode', {
  6549. pressed: [
  6550. defaulted('syncWithExpanded', false),
  6551. output$1('update', updatePressed)
  6552. ],
  6553. checked: [output$1('update', updateChecked)],
  6554. expanded: [output$1('update', updateExpanded)],
  6555. selected: [output$1('update', updateSelected)],
  6556. none: [output$1('update', noop)]
  6557. }))
  6558. ];
  6559. const Toggling = create$3({
  6560. fields: ToggleSchema,
  6561. name: 'toggling',
  6562. active: ActiveToggle,
  6563. apis: ToggleApis,
  6564. state: SetupBehaviourCellState(false)
  6565. });
  6566. const pointerEvents = () => {
  6567. const onClick = (component, simulatedEvent) => {
  6568. simulatedEvent.stop();
  6569. emitExecute(component);
  6570. };
  6571. return [
  6572. run$1(click(), onClick),
  6573. run$1(tap(), onClick),
  6574. cutter(touchstart()),
  6575. cutter(mousedown())
  6576. ];
  6577. };
  6578. const events$a = optAction => {
  6579. const executeHandler = action => runOnExecute$1((component, simulatedEvent) => {
  6580. action(component);
  6581. simulatedEvent.stop();
  6582. });
  6583. return derive$2(flatten([
  6584. optAction.map(executeHandler).toArray(),
  6585. pointerEvents()
  6586. ]));
  6587. };
  6588. const hoverEvent = 'alloy.item-hover';
  6589. const focusEvent = 'alloy.item-focus';
  6590. const toggledEvent = 'alloy.item-toggled';
  6591. const onHover = item => {
  6592. if (search(item.element).isNone() || Focusing.isFocused(item)) {
  6593. if (!Focusing.isFocused(item)) {
  6594. Focusing.focus(item);
  6595. }
  6596. emitWith(item, hoverEvent, { item });
  6597. }
  6598. };
  6599. const onFocus$1 = item => {
  6600. emitWith(item, focusEvent, { item });
  6601. };
  6602. const onToggled = (item, state) => {
  6603. emitWith(item, toggledEvent, {
  6604. item,
  6605. state
  6606. });
  6607. };
  6608. const hover = constant$1(hoverEvent);
  6609. const focus$1 = constant$1(focusEvent);
  6610. const toggled = constant$1(toggledEvent);
  6611. const getItemRole = detail => detail.toggling.map(toggling => toggling.exclusive ? 'menuitemradio' : 'menuitemcheckbox').getOr('menuitem');
  6612. const getTogglingSpec = tConfig => ({
  6613. aria: { mode: 'checked' },
  6614. ...filter$1(tConfig, (_value, name) => name !== 'exclusive'),
  6615. onToggled: (component, state) => {
  6616. if (isFunction(tConfig.onToggled)) {
  6617. tConfig.onToggled(component, state);
  6618. }
  6619. onToggled(component, state);
  6620. }
  6621. });
  6622. const builder$2 = detail => ({
  6623. dom: detail.dom,
  6624. domModification: {
  6625. ...detail.domModification,
  6626. attributes: {
  6627. 'role': getItemRole(detail),
  6628. ...detail.domModification.attributes,
  6629. 'aria-haspopup': detail.hasSubmenu,
  6630. ...detail.hasSubmenu ? { 'aria-expanded': false } : {}
  6631. }
  6632. },
  6633. behaviours: SketchBehaviours.augment(detail.itemBehaviours, [
  6634. detail.toggling.fold(Toggling.revoke, tConfig => Toggling.config(getTogglingSpec(tConfig))),
  6635. Focusing.config({
  6636. ignore: detail.ignoreFocus,
  6637. stopMousedown: detail.ignoreFocus,
  6638. onFocus: component => {
  6639. onFocus$1(component);
  6640. }
  6641. }),
  6642. Keying.config({ mode: 'execution' }),
  6643. Representing.config({
  6644. store: {
  6645. mode: 'memory',
  6646. initialValue: detail.data
  6647. }
  6648. }),
  6649. config('item-type-events', [
  6650. ...pointerEvents(),
  6651. run$1(mouseover(), onHover),
  6652. run$1(focusItem(), Focusing.focus)
  6653. ])
  6654. ]),
  6655. components: detail.components,
  6656. eventOrder: detail.eventOrder
  6657. });
  6658. const schema$p = [
  6659. required$1('data'),
  6660. required$1('components'),
  6661. required$1('dom'),
  6662. defaulted('hasSubmenu', false),
  6663. option$3('toggling'),
  6664. SketchBehaviours.field('itemBehaviours', [
  6665. Toggling,
  6666. Focusing,
  6667. Keying,
  6668. Representing
  6669. ]),
  6670. defaulted('ignoreFocus', false),
  6671. defaulted('domModification', {}),
  6672. output$1('builder', builder$2),
  6673. defaulted('eventOrder', {})
  6674. ];
  6675. const builder$1 = detail => ({
  6676. dom: detail.dom,
  6677. components: detail.components,
  6678. events: derive$2([stopper(focusItem())])
  6679. });
  6680. const schema$o = [
  6681. required$1('dom'),
  6682. required$1('components'),
  6683. output$1('builder', builder$1)
  6684. ];
  6685. const owner$2 = constant$1('item-widget');
  6686. const parts$h = constant$1([required({
  6687. name: 'widget',
  6688. overrides: detail => {
  6689. return {
  6690. behaviours: derive$1([Representing.config({
  6691. store: {
  6692. mode: 'manual',
  6693. getValue: _component => {
  6694. return detail.data;
  6695. },
  6696. setValue: noop
  6697. }
  6698. })])
  6699. };
  6700. }
  6701. })]);
  6702. const builder = detail => {
  6703. const subs = substitutes(owner$2(), detail, parts$h());
  6704. const components = components$1(owner$2(), detail, subs.internals());
  6705. const focusWidget = component => getPart(component, detail, 'widget').map(widget => {
  6706. Keying.focusIn(widget);
  6707. return widget;
  6708. });
  6709. const onHorizontalArrow = (component, simulatedEvent) => inside(simulatedEvent.event.target) ? Optional.none() : (() => {
  6710. if (detail.autofocus) {
  6711. simulatedEvent.setSource(component.element);
  6712. return Optional.none();
  6713. } else {
  6714. return Optional.none();
  6715. }
  6716. })();
  6717. return {
  6718. dom: detail.dom,
  6719. components,
  6720. domModification: detail.domModification,
  6721. events: derive$2([
  6722. runOnExecute$1((component, simulatedEvent) => {
  6723. focusWidget(component).each(_widget => {
  6724. simulatedEvent.stop();
  6725. });
  6726. }),
  6727. run$1(mouseover(), onHover),
  6728. run$1(focusItem(), (component, _simulatedEvent) => {
  6729. if (detail.autofocus) {
  6730. focusWidget(component);
  6731. } else {
  6732. Focusing.focus(component);
  6733. }
  6734. })
  6735. ]),
  6736. behaviours: SketchBehaviours.augment(detail.widgetBehaviours, [
  6737. Representing.config({
  6738. store: {
  6739. mode: 'memory',
  6740. initialValue: detail.data
  6741. }
  6742. }),
  6743. Focusing.config({
  6744. ignore: detail.ignoreFocus,
  6745. onFocus: component => {
  6746. onFocus$1(component);
  6747. }
  6748. }),
  6749. Keying.config({
  6750. mode: 'special',
  6751. focusIn: detail.autofocus ? component => {
  6752. focusWidget(component);
  6753. } : revoke(),
  6754. onLeft: onHorizontalArrow,
  6755. onRight: onHorizontalArrow,
  6756. onEscape: (component, simulatedEvent) => {
  6757. if (!Focusing.isFocused(component) && !detail.autofocus) {
  6758. Focusing.focus(component);
  6759. return Optional.some(true);
  6760. } else if (detail.autofocus) {
  6761. simulatedEvent.setSource(component.element);
  6762. return Optional.none();
  6763. } else {
  6764. return Optional.none();
  6765. }
  6766. }
  6767. })
  6768. ])
  6769. };
  6770. };
  6771. const schema$n = [
  6772. required$1('uid'),
  6773. required$1('data'),
  6774. required$1('components'),
  6775. required$1('dom'),
  6776. defaulted('autofocus', false),
  6777. defaulted('ignoreFocus', false),
  6778. SketchBehaviours.field('widgetBehaviours', [
  6779. Representing,
  6780. Focusing,
  6781. Keying
  6782. ]),
  6783. defaulted('domModification', {}),
  6784. defaultUidsSchema(parts$h()),
  6785. output$1('builder', builder)
  6786. ];
  6787. const itemSchema$2 = choose$1('type', {
  6788. widget: schema$n,
  6789. item: schema$p,
  6790. separator: schema$o
  6791. });
  6792. const configureGrid = (detail, movementInfo) => ({
  6793. mode: 'flatgrid',
  6794. selector: '.' + detail.markers.item,
  6795. initSize: {
  6796. numColumns: movementInfo.initSize.numColumns,
  6797. numRows: movementInfo.initSize.numRows
  6798. },
  6799. focusManager: detail.focusManager
  6800. });
  6801. const configureMatrix = (detail, movementInfo) => ({
  6802. mode: 'matrix',
  6803. selectors: {
  6804. row: movementInfo.rowSelector,
  6805. cell: '.' + detail.markers.item
  6806. },
  6807. focusManager: detail.focusManager
  6808. });
  6809. const configureMenu = (detail, movementInfo) => ({
  6810. mode: 'menu',
  6811. selector: '.' + detail.markers.item,
  6812. moveOnTab: movementInfo.moveOnTab,
  6813. focusManager: detail.focusManager
  6814. });
  6815. const parts$g = constant$1([group({
  6816. factory: {
  6817. sketch: spec => {
  6818. const itemInfo = asRawOrDie$1('menu.spec item', itemSchema$2, spec);
  6819. return itemInfo.builder(itemInfo);
  6820. }
  6821. },
  6822. name: 'items',
  6823. unit: 'item',
  6824. defaults: (detail, u) => {
  6825. return has$2(u, 'uid') ? u : {
  6826. ...u,
  6827. uid: generate$5('item')
  6828. };
  6829. },
  6830. overrides: (detail, u) => {
  6831. return {
  6832. type: u.type,
  6833. ignoreFocus: detail.fakeFocus,
  6834. domModification: { classes: [detail.markers.item] }
  6835. };
  6836. }
  6837. })]);
  6838. const schema$m = constant$1([
  6839. required$1('value'),
  6840. required$1('items'),
  6841. required$1('dom'),
  6842. required$1('components'),
  6843. defaulted('eventOrder', {}),
  6844. field('menuBehaviours', [
  6845. Highlighting,
  6846. Representing,
  6847. Composing,
  6848. Keying
  6849. ]),
  6850. defaultedOf('movement', {
  6851. mode: 'menu',
  6852. moveOnTab: true
  6853. }, choose$1('mode', {
  6854. grid: [
  6855. initSize(),
  6856. output$1('config', configureGrid)
  6857. ],
  6858. matrix: [
  6859. output$1('config', configureMatrix),
  6860. required$1('rowSelector')
  6861. ],
  6862. menu: [
  6863. defaulted('moveOnTab', true),
  6864. output$1('config', configureMenu)
  6865. ]
  6866. })),
  6867. itemMarkers(),
  6868. defaulted('fakeFocus', false),
  6869. defaulted('focusManager', dom$2()),
  6870. onHandler('onHighlight')
  6871. ]);
  6872. const focus = constant$1('alloy.menu-focus');
  6873. const deselectOtherRadioItems = (menu, item) => {
  6874. const checkedRadioItems = descendants(menu.element, '[role="menuitemradio"][aria-checked="true"]');
  6875. each$1(checkedRadioItems, ele => {
  6876. if (!eq(ele, item.element)) {
  6877. menu.getSystem().getByDom(ele).each(c => {
  6878. Toggling.off(c);
  6879. });
  6880. }
  6881. });
  6882. };
  6883. const make$7 = (detail, components, _spec, _externals) => ({
  6884. uid: detail.uid,
  6885. dom: detail.dom,
  6886. markers: detail.markers,
  6887. behaviours: augment(detail.menuBehaviours, [
  6888. Highlighting.config({
  6889. highlightClass: detail.markers.selectedItem,
  6890. itemClass: detail.markers.item,
  6891. onHighlight: detail.onHighlight
  6892. }),
  6893. Representing.config({
  6894. store: {
  6895. mode: 'memory',
  6896. initialValue: detail.value
  6897. }
  6898. }),
  6899. Composing.config({ find: Optional.some }),
  6900. Keying.config(detail.movement.config(detail, detail.movement))
  6901. ]),
  6902. events: derive$2([
  6903. run$1(focus$1(), (menu, simulatedEvent) => {
  6904. const event = simulatedEvent.event;
  6905. menu.getSystem().getByDom(event.target).each(item => {
  6906. Highlighting.highlight(menu, item);
  6907. simulatedEvent.stop();
  6908. emitWith(menu, focus(), {
  6909. menu,
  6910. item
  6911. });
  6912. });
  6913. }),
  6914. run$1(hover(), (menu, simulatedEvent) => {
  6915. const item = simulatedEvent.event.item;
  6916. Highlighting.highlight(menu, item);
  6917. }),
  6918. run$1(toggled(), (menu, simulatedEvent) => {
  6919. const {item, state} = simulatedEvent.event;
  6920. if (state && get$f(item.element, 'role') === 'menuitemradio') {
  6921. deselectOtherRadioItems(menu, item);
  6922. }
  6923. })
  6924. ]),
  6925. components,
  6926. eventOrder: detail.eventOrder,
  6927. domModification: { attributes: { role: 'menu' } }
  6928. });
  6929. const Menu = composite({
  6930. name: 'Menu',
  6931. configFields: schema$m(),
  6932. partFields: parts$g(),
  6933. factory: make$7
  6934. });
  6935. const transpose$1 = obj => tupleMap(obj, (v, k) => ({
  6936. k: v,
  6937. v: k
  6938. }));
  6939. const trace = (items, byItem, byMenu, finish) => get$g(byMenu, finish).bind(triggerItem => get$g(items, triggerItem).bind(triggerMenu => {
  6940. const rest = trace(items, byItem, byMenu, triggerMenu);
  6941. return Optional.some([triggerMenu].concat(rest));
  6942. })).getOr([]);
  6943. const generate$2 = (menus, expansions) => {
  6944. const items = {};
  6945. each(menus, (menuItems, menu) => {
  6946. each$1(menuItems, item => {
  6947. items[item] = menu;
  6948. });
  6949. });
  6950. const byItem = expansions;
  6951. const byMenu = transpose$1(expansions);
  6952. const menuPaths = map$1(byMenu, (_triggerItem, submenu) => [submenu].concat(trace(items, byItem, byMenu, submenu)));
  6953. return map$1(items, menu => get$g(menuPaths, menu).getOr([menu]));
  6954. };
  6955. const init$c = () => {
  6956. const expansions = Cell({});
  6957. const menus = Cell({});
  6958. const paths = Cell({});
  6959. const primary = value$2();
  6960. const directory = Cell({});
  6961. const clear = () => {
  6962. expansions.set({});
  6963. menus.set({});
  6964. paths.set({});
  6965. primary.clear();
  6966. };
  6967. const isClear = () => primary.get().isNone();
  6968. const setMenuBuilt = (menuName, built) => {
  6969. menus.set({
  6970. ...menus.get(),
  6971. [menuName]: {
  6972. type: 'prepared',
  6973. menu: built
  6974. }
  6975. });
  6976. };
  6977. const setContents = (sPrimary, sMenus, sExpansions, dir) => {
  6978. primary.set(sPrimary);
  6979. expansions.set(sExpansions);
  6980. menus.set(sMenus);
  6981. directory.set(dir);
  6982. const sPaths = generate$2(dir, sExpansions);
  6983. paths.set(sPaths);
  6984. };
  6985. const getTriggeringItem = menuValue => find$4(expansions.get(), (v, _k) => v === menuValue);
  6986. const getTriggerData = (menuValue, getItemByValue, path) => getPreparedMenu(menuValue).bind(menu => getTriggeringItem(menuValue).bind(triggeringItemValue => getItemByValue(triggeringItemValue).map(triggeredItem => ({
  6987. triggeredMenu: menu,
  6988. triggeringItem: triggeredItem,
  6989. triggeringPath: path
  6990. }))));
  6991. const getTriggeringPath = (itemValue, getItemByValue) => {
  6992. const extraPath = filter$2(lookupItem(itemValue).toArray(), menuValue => getPreparedMenu(menuValue).isSome());
  6993. return get$g(paths.get(), itemValue).bind(path => {
  6994. const revPath = reverse(extraPath.concat(path));
  6995. 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)]));
  6996. return sequence(triggers);
  6997. });
  6998. };
  6999. const expand = itemValue => get$g(expansions.get(), itemValue).map(menu => {
  7000. const current = get$g(paths.get(), itemValue).getOr([]);
  7001. return [menu].concat(current);
  7002. });
  7003. const collapse = itemValue => get$g(paths.get(), itemValue).bind(path => path.length > 1 ? Optional.some(path.slice(1)) : Optional.none());
  7004. const refresh = itemValue => get$g(paths.get(), itemValue);
  7005. const getPreparedMenu = menuValue => lookupMenu(menuValue).bind(extractPreparedMenu);
  7006. const lookupMenu = menuValue => get$g(menus.get(), menuValue);
  7007. const lookupItem = itemValue => get$g(expansions.get(), itemValue);
  7008. const otherMenus = path => {
  7009. const menuValues = directory.get();
  7010. return difference(keys(menuValues), path);
  7011. };
  7012. const getPrimary = () => primary.get().bind(getPreparedMenu);
  7013. const getMenus = () => menus.get();
  7014. return {
  7015. setMenuBuilt,
  7016. setContents,
  7017. expand,
  7018. refresh,
  7019. collapse,
  7020. lookupMenu,
  7021. lookupItem,
  7022. otherMenus,
  7023. getPrimary,
  7024. getMenus,
  7025. clear,
  7026. isClear,
  7027. getTriggeringPath
  7028. };
  7029. };
  7030. const extractPreparedMenu = prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none();
  7031. const LayeredState = {
  7032. init: init$c,
  7033. extractPreparedMenu
  7034. };
  7035. const make$6 = (detail, _rawUiSpec) => {
  7036. const submenuParentItems = value$2();
  7037. const buildMenus = (container, primaryName, menus) => map$1(menus, (spec, name) => {
  7038. const makeSketch = () => Menu.sketch({
  7039. ...spec,
  7040. value: name,
  7041. markers: detail.markers,
  7042. fakeFocus: detail.fakeFocus,
  7043. onHighlight: detail.onHighlight,
  7044. focusManager: detail.fakeFocus ? highlights() : dom$2()
  7045. });
  7046. return name === primaryName ? {
  7047. type: 'prepared',
  7048. menu: container.getSystem().build(makeSketch())
  7049. } : {
  7050. type: 'notbuilt',
  7051. nbMenu: makeSketch
  7052. };
  7053. });
  7054. const layeredState = LayeredState.init();
  7055. const setup = container => {
  7056. const componentMap = buildMenus(container, detail.data.primary, detail.data.menus);
  7057. const directory = toDirectory();
  7058. layeredState.setContents(detail.data.primary, componentMap, detail.data.expansions, directory);
  7059. return layeredState.getPrimary();
  7060. };
  7061. const getItemValue = item => Representing.getValue(item).value;
  7062. const getItemByValue = (_container, menus, itemValue) => findMap(menus, menu => {
  7063. if (!menu.getSystem().isConnected()) {
  7064. return Optional.none();
  7065. }
  7066. const candidates = Highlighting.getCandidates(menu);
  7067. return find$5(candidates, c => getItemValue(c) === itemValue);
  7068. });
  7069. const toDirectory = _container => map$1(detail.data.menus, (data, _menuName) => bind$3(data.items, item => item.type === 'separator' ? [] : [item.data.value]));
  7070. const setActiveMenu = (container, menu) => {
  7071. Highlighting.highlight(container, menu);
  7072. Highlighting.getHighlighted(menu).orThunk(() => Highlighting.getFirst(menu)).each(item => {
  7073. dispatch(container, item.element, focusItem());
  7074. });
  7075. };
  7076. const getMenus = (state, menuValues) => cat(map$2(menuValues, mv => state.lookupMenu(mv).bind(prep => prep.type === 'prepared' ? Optional.some(prep.menu) : Optional.none())));
  7077. const closeOthers = (container, state, path) => {
  7078. const others = getMenus(state, state.otherMenus(path));
  7079. each$1(others, o => {
  7080. remove$1(o.element, [detail.markers.backgroundMenu]);
  7081. if (!detail.stayInDom) {
  7082. Replacing.remove(container, o);
  7083. }
  7084. });
  7085. };
  7086. const getSubmenuParents = container => submenuParentItems.get().getOrThunk(() => {
  7087. const r = {};
  7088. const items = descendants(container.element, `.${ detail.markers.item }`);
  7089. const parentItems = filter$2(items, i => get$f(i, 'aria-haspopup') === 'true');
  7090. each$1(parentItems, i => {
  7091. container.getSystem().getByDom(i).each(itemComp => {
  7092. const key = getItemValue(itemComp);
  7093. r[key] = itemComp;
  7094. });
  7095. });
  7096. submenuParentItems.set(r);
  7097. return r;
  7098. });
  7099. const updateAriaExpansions = (container, path) => {
  7100. const parentItems = getSubmenuParents(container);
  7101. each(parentItems, (v, k) => {
  7102. const expanded = contains$2(path, k);
  7103. set$9(v.element, 'aria-expanded', expanded);
  7104. });
  7105. };
  7106. const updateMenuPath = (container, state, path) => Optional.from(path[0]).bind(latestMenuName => state.lookupMenu(latestMenuName).bind(menuPrep => {
  7107. if (menuPrep.type === 'notbuilt') {
  7108. return Optional.none();
  7109. } else {
  7110. const activeMenu = menuPrep.menu;
  7111. const rest = getMenus(state, path.slice(1));
  7112. each$1(rest, r => {
  7113. add$2(r.element, detail.markers.backgroundMenu);
  7114. });
  7115. if (!inBody(activeMenu.element)) {
  7116. Replacing.append(container, premade(activeMenu));
  7117. }
  7118. remove$1(activeMenu.element, [detail.markers.backgroundMenu]);
  7119. setActiveMenu(container, activeMenu);
  7120. closeOthers(container, state, path);
  7121. return Optional.some(activeMenu);
  7122. }
  7123. }));
  7124. let ExpandHighlightDecision;
  7125. (function (ExpandHighlightDecision) {
  7126. ExpandHighlightDecision[ExpandHighlightDecision['HighlightSubmenu'] = 0] = 'HighlightSubmenu';
  7127. ExpandHighlightDecision[ExpandHighlightDecision['HighlightParent'] = 1] = 'HighlightParent';
  7128. }(ExpandHighlightDecision || (ExpandHighlightDecision = {})));
  7129. const buildIfRequired = (container, menuName, menuPrep) => {
  7130. if (menuPrep.type === 'notbuilt') {
  7131. const menu = container.getSystem().build(menuPrep.nbMenu());
  7132. layeredState.setMenuBuilt(menuName, menu);
  7133. return menu;
  7134. } else {
  7135. return menuPrep.menu;
  7136. }
  7137. };
  7138. const expandRight = (container, item, decision = ExpandHighlightDecision.HighlightSubmenu) => {
  7139. if (item.hasConfigured(Disabling) && Disabling.isDisabled(item)) {
  7140. return Optional.some(item);
  7141. } else {
  7142. const value = getItemValue(item);
  7143. return layeredState.expand(value).bind(path => {
  7144. updateAriaExpansions(container, path);
  7145. return Optional.from(path[0]).bind(menuName => layeredState.lookupMenu(menuName).bind(activeMenuPrep => {
  7146. const activeMenu = buildIfRequired(container, menuName, activeMenuPrep);
  7147. if (!inBody(activeMenu.element)) {
  7148. Replacing.append(container, premade(activeMenu));
  7149. }
  7150. detail.onOpenSubmenu(container, item, activeMenu, reverse(path));
  7151. if (decision === ExpandHighlightDecision.HighlightSubmenu) {
  7152. Highlighting.highlightFirst(activeMenu);
  7153. return updateMenuPath(container, layeredState, path);
  7154. } else {
  7155. Highlighting.dehighlightAll(activeMenu);
  7156. return Optional.some(item);
  7157. }
  7158. }));
  7159. });
  7160. }
  7161. };
  7162. const collapseLeft = (container, item) => {
  7163. const value = getItemValue(item);
  7164. return layeredState.collapse(value).bind(path => {
  7165. updateAriaExpansions(container, path);
  7166. return updateMenuPath(container, layeredState, path).map(activeMenu => {
  7167. detail.onCollapseMenu(container, item, activeMenu);
  7168. return activeMenu;
  7169. });
  7170. });
  7171. };
  7172. const updateView = (container, item) => {
  7173. const value = getItemValue(item);
  7174. return layeredState.refresh(value).bind(path => {
  7175. updateAriaExpansions(container, path);
  7176. return updateMenuPath(container, layeredState, path);
  7177. });
  7178. };
  7179. const onRight = (container, item) => inside(item.element) ? Optional.none() : expandRight(container, item, ExpandHighlightDecision.HighlightSubmenu);
  7180. const onLeft = (container, item) => inside(item.element) ? Optional.none() : collapseLeft(container, item);
  7181. const onEscape = (container, item) => collapseLeft(container, item).orThunk(() => detail.onEscape(container, item).map(() => container));
  7182. const keyOnItem = f => (container, simulatedEvent) => closest$1(simulatedEvent.getSource(), '.' + detail.markers.item).bind(target => container.getSystem().getByDom(target).toOptional().bind(item => f(container, item).map(always)));
  7183. const events = derive$2([
  7184. run$1(focus(), (sandbox, simulatedEvent) => {
  7185. const item = simulatedEvent.event.item;
  7186. layeredState.lookupItem(getItemValue(item)).each(() => {
  7187. const menu = simulatedEvent.event.menu;
  7188. Highlighting.highlight(sandbox, menu);
  7189. const value = getItemValue(simulatedEvent.event.item);
  7190. layeredState.refresh(value).each(path => closeOthers(sandbox, layeredState, path));
  7191. });
  7192. }),
  7193. runOnExecute$1((component, simulatedEvent) => {
  7194. const target = simulatedEvent.event.target;
  7195. component.getSystem().getByDom(target).each(item => {
  7196. const itemValue = getItemValue(item);
  7197. if (itemValue.indexOf('collapse-item') === 0) {
  7198. collapseLeft(component, item);
  7199. }
  7200. expandRight(component, item, ExpandHighlightDecision.HighlightSubmenu).fold(() => {
  7201. detail.onExecute(component, item);
  7202. }, noop);
  7203. });
  7204. }),
  7205. runOnAttached((container, _simulatedEvent) => {
  7206. setup(container).each(primary => {
  7207. Replacing.append(container, premade(primary));
  7208. detail.onOpenMenu(container, primary);
  7209. if (detail.highlightImmediately) {
  7210. setActiveMenu(container, primary);
  7211. }
  7212. });
  7213. })
  7214. ].concat(detail.navigateOnHover ? [run$1(hover(), (sandbox, simulatedEvent) => {
  7215. const item = simulatedEvent.event.item;
  7216. updateView(sandbox, item);
  7217. expandRight(sandbox, item, ExpandHighlightDecision.HighlightParent);
  7218. detail.onHover(sandbox, item);
  7219. })] : []));
  7220. const getActiveItem = container => Highlighting.getHighlighted(container).bind(Highlighting.getHighlighted);
  7221. const collapseMenuApi = container => {
  7222. getActiveItem(container).each(currentItem => {
  7223. collapseLeft(container, currentItem);
  7224. });
  7225. };
  7226. const highlightPrimary = container => {
  7227. layeredState.getPrimary().each(primary => {
  7228. setActiveMenu(container, primary);
  7229. });
  7230. };
  7231. const extractMenuFromContainer = container => Optional.from(container.components()[0]).filter(comp => get$f(comp.element, 'role') === 'menu');
  7232. const repositionMenus = container => {
  7233. const maybeActivePrimary = layeredState.getPrimary().bind(primary => getActiveItem(container).bind(currentItem => {
  7234. const itemValue = getItemValue(currentItem);
  7235. const allMenus = values(layeredState.getMenus());
  7236. const preparedMenus = cat(map$2(allMenus, LayeredState.extractPreparedMenu));
  7237. return layeredState.getTriggeringPath(itemValue, v => getItemByValue(container, preparedMenus, v));
  7238. }).map(triggeringPath => ({
  7239. primary,
  7240. triggeringPath
  7241. })));
  7242. maybeActivePrimary.fold(() => {
  7243. extractMenuFromContainer(container).each(primaryMenu => {
  7244. detail.onRepositionMenu(container, primaryMenu, []);
  7245. });
  7246. }, ({primary, triggeringPath}) => {
  7247. detail.onRepositionMenu(container, primary, triggeringPath);
  7248. });
  7249. };
  7250. const apis = {
  7251. collapseMenu: collapseMenuApi,
  7252. highlightPrimary,
  7253. repositionMenus
  7254. };
  7255. return {
  7256. uid: detail.uid,
  7257. dom: detail.dom,
  7258. markers: detail.markers,
  7259. behaviours: augment(detail.tmenuBehaviours, [
  7260. Keying.config({
  7261. mode: 'special',
  7262. onRight: keyOnItem(onRight),
  7263. onLeft: keyOnItem(onLeft),
  7264. onEscape: keyOnItem(onEscape),
  7265. focusIn: (container, _keyInfo) => {
  7266. layeredState.getPrimary().each(primary => {
  7267. dispatch(container, primary.element, focusItem());
  7268. });
  7269. }
  7270. }),
  7271. Highlighting.config({
  7272. highlightClass: detail.markers.selectedMenu,
  7273. itemClass: detail.markers.menu
  7274. }),
  7275. Composing.config({
  7276. find: container => {
  7277. return Highlighting.getHighlighted(container);
  7278. }
  7279. }),
  7280. Replacing.config({})
  7281. ]),
  7282. eventOrder: detail.eventOrder,
  7283. apis,
  7284. events
  7285. };
  7286. };
  7287. const collapseItem$1 = constant$1('collapse-item');
  7288. const tieredData = (primary, menus, expansions) => ({
  7289. primary,
  7290. menus,
  7291. expansions
  7292. });
  7293. const singleData = (name, menu) => ({
  7294. primary: name,
  7295. menus: wrap$1(name, menu),
  7296. expansions: {}
  7297. });
  7298. const collapseItem = text => ({
  7299. value: generate$6(collapseItem$1()),
  7300. meta: { text }
  7301. });
  7302. const tieredMenu = single({
  7303. name: 'TieredMenu',
  7304. configFields: [
  7305. onStrictKeyboardHandler('onExecute'),
  7306. onStrictKeyboardHandler('onEscape'),
  7307. onStrictHandler('onOpenMenu'),
  7308. onStrictHandler('onOpenSubmenu'),
  7309. onHandler('onRepositionMenu'),
  7310. onHandler('onCollapseMenu'),
  7311. defaulted('highlightImmediately', true),
  7312. requiredObjOf('data', [
  7313. required$1('primary'),
  7314. required$1('menus'),
  7315. required$1('expansions')
  7316. ]),
  7317. defaulted('fakeFocus', false),
  7318. onHandler('onHighlight'),
  7319. onHandler('onHover'),
  7320. tieredMenuMarkers(),
  7321. required$1('dom'),
  7322. defaulted('navigateOnHover', true),
  7323. defaulted('stayInDom', false),
  7324. field('tmenuBehaviours', [
  7325. Keying,
  7326. Highlighting,
  7327. Composing,
  7328. Replacing
  7329. ]),
  7330. defaulted('eventOrder', {})
  7331. ],
  7332. apis: {
  7333. collapseMenu: (apis, tmenu) => {
  7334. apis.collapseMenu(tmenu);
  7335. },
  7336. highlightPrimary: (apis, tmenu) => {
  7337. apis.highlightPrimary(tmenu);
  7338. },
  7339. repositionMenus: (apis, tmenu) => {
  7340. apis.repositionMenus(tmenu);
  7341. }
  7342. },
  7343. factory: make$6,
  7344. extraApis: {
  7345. tieredData,
  7346. singleData,
  7347. collapseItem
  7348. }
  7349. });
  7350. const makeMenu = (detail, menuSandbox, placementSpec, menuSpec, getBounds) => {
  7351. const lazySink = () => detail.lazySink(menuSandbox);
  7352. const layouts = menuSpec.type === 'horizontal' ? {
  7353. layouts: {
  7354. onLtr: () => belowOrAbove(),
  7355. onRtl: () => belowOrAboveRtl()
  7356. }
  7357. } : {};
  7358. const isFirstTierSubmenu = triggeringPaths => triggeringPaths.length === 2;
  7359. const getSubmenuLayouts = triggeringPaths => isFirstTierSubmenu(triggeringPaths) ? layouts : {};
  7360. return tieredMenu.sketch({
  7361. dom: { tag: 'div' },
  7362. data: menuSpec.data,
  7363. markers: menuSpec.menu.markers,
  7364. highlightImmediately: menuSpec.menu.highlightImmediately,
  7365. fakeFocus: menuSpec.menu.fakeFocus,
  7366. onEscape: () => {
  7367. Sandboxing.close(menuSandbox);
  7368. detail.onEscape.map(handler => handler(menuSandbox));
  7369. return Optional.some(true);
  7370. },
  7371. onExecute: () => {
  7372. return Optional.some(true);
  7373. },
  7374. onOpenMenu: (tmenu, menu) => {
  7375. Positioning.positionWithinBounds(lazySink().getOrDie(), menu, placementSpec, getBounds());
  7376. },
  7377. onOpenSubmenu: (tmenu, item, submenu, triggeringPaths) => {
  7378. const sink = lazySink().getOrDie();
  7379. Positioning.position(sink, submenu, {
  7380. anchor: {
  7381. type: 'submenu',
  7382. item,
  7383. ...getSubmenuLayouts(triggeringPaths)
  7384. }
  7385. });
  7386. },
  7387. onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
  7388. const sink = lazySink().getOrDie();
  7389. Positioning.positionWithinBounds(sink, primaryMenu, placementSpec, getBounds());
  7390. each$1(submenuTriggers, st => {
  7391. const submenuLayouts = getSubmenuLayouts(st.triggeringPath);
  7392. Positioning.position(sink, st.triggeredMenu, {
  7393. anchor: {
  7394. type: 'submenu',
  7395. item: st.triggeringItem,
  7396. ...submenuLayouts
  7397. }
  7398. });
  7399. });
  7400. }
  7401. });
  7402. };
  7403. const factory$m = (detail, spec) => {
  7404. const isPartOfRelated = (sandbox, queryElem) => {
  7405. const related = detail.getRelated(sandbox);
  7406. return related.exists(rel => isPartOf$1(rel, queryElem));
  7407. };
  7408. const setContent = (sandbox, thing) => {
  7409. Sandboxing.setContent(sandbox, thing);
  7410. };
  7411. const showAt = (sandbox, thing, placementSpec) => {
  7412. showWithin(sandbox, thing, placementSpec, Optional.none());
  7413. };
  7414. const showWithin = (sandbox, thing, placementSpec, boxElement) => {
  7415. showWithinBounds(sandbox, thing, placementSpec, () => boxElement.map(elem => box$1(elem)));
  7416. };
  7417. const showWithinBounds = (sandbox, thing, placementSpec, getBounds) => {
  7418. const sink = detail.lazySink(sandbox).getOrDie();
  7419. Sandboxing.openWhileCloaked(sandbox, thing, () => Positioning.positionWithinBounds(sink, sandbox, placementSpec, getBounds()));
  7420. Representing.setValue(sandbox, Optional.some({
  7421. mode: 'position',
  7422. config: placementSpec,
  7423. getBounds
  7424. }));
  7425. };
  7426. const showMenuAt = (sandbox, placementSpec, menuSpec) => {
  7427. showMenuWithinBounds(sandbox, placementSpec, menuSpec, Optional.none);
  7428. };
  7429. const showMenuWithinBounds = (sandbox, placementSpec, menuSpec, getBounds) => {
  7430. const menu = makeMenu(detail, sandbox, placementSpec, menuSpec, getBounds);
  7431. Sandboxing.open(sandbox, menu);
  7432. Representing.setValue(sandbox, Optional.some({
  7433. mode: 'menu',
  7434. menu
  7435. }));
  7436. };
  7437. const hide = sandbox => {
  7438. if (Sandboxing.isOpen(sandbox)) {
  7439. Representing.setValue(sandbox, Optional.none());
  7440. Sandboxing.close(sandbox);
  7441. }
  7442. };
  7443. const getContent = sandbox => Sandboxing.getState(sandbox);
  7444. const reposition = sandbox => {
  7445. if (Sandboxing.isOpen(sandbox)) {
  7446. Representing.getValue(sandbox).each(state => {
  7447. switch (state.mode) {
  7448. case 'menu':
  7449. Sandboxing.getState(sandbox).each(tieredMenu.repositionMenus);
  7450. break;
  7451. case 'position':
  7452. const sink = detail.lazySink(sandbox).getOrDie();
  7453. Positioning.positionWithinBounds(sink, sandbox, state.config, state.getBounds());
  7454. break;
  7455. }
  7456. });
  7457. }
  7458. };
  7459. const apis = {
  7460. setContent,
  7461. showAt,
  7462. showWithin,
  7463. showWithinBounds,
  7464. showMenuAt,
  7465. showMenuWithinBounds,
  7466. hide,
  7467. getContent,
  7468. reposition,
  7469. isOpen: Sandboxing.isOpen
  7470. };
  7471. return {
  7472. uid: detail.uid,
  7473. dom: detail.dom,
  7474. behaviours: augment(detail.inlineBehaviours, [
  7475. Sandboxing.config({
  7476. isPartOf: (sandbox, data, queryElem) => {
  7477. return isPartOf$1(data, queryElem) || isPartOfRelated(sandbox, queryElem);
  7478. },
  7479. getAttachPoint: sandbox => {
  7480. return detail.lazySink(sandbox).getOrDie();
  7481. },
  7482. onOpen: sandbox => {
  7483. detail.onShow(sandbox);
  7484. },
  7485. onClose: sandbox => {
  7486. detail.onHide(sandbox);
  7487. }
  7488. }),
  7489. Representing.config({
  7490. store: {
  7491. mode: 'memory',
  7492. initialValue: Optional.none()
  7493. }
  7494. }),
  7495. Receiving.config({
  7496. channels: {
  7497. ...receivingChannel$1({
  7498. isExtraPart: spec.isExtraPart,
  7499. ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
  7500. }),
  7501. ...receivingChannel({
  7502. ...detail.fireRepositionEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({}),
  7503. doReposition: reposition
  7504. })
  7505. }
  7506. })
  7507. ]),
  7508. eventOrder: detail.eventOrder,
  7509. apis
  7510. };
  7511. };
  7512. const InlineView = single({
  7513. name: 'InlineView',
  7514. configFields: [
  7515. required$1('lazySink'),
  7516. onHandler('onShow'),
  7517. onHandler('onHide'),
  7518. optionFunction('onEscape'),
  7519. field('inlineBehaviours', [
  7520. Sandboxing,
  7521. Representing,
  7522. Receiving
  7523. ]),
  7524. optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
  7525. optionObjOf('fireRepositionEventInstead', [defaulted('event', repositionRequested())]),
  7526. defaulted('getRelated', Optional.none),
  7527. defaulted('isExtraPart', never),
  7528. defaulted('eventOrder', Optional.none)
  7529. ],
  7530. factory: factory$m,
  7531. apis: {
  7532. showAt: (apis, component, anchor, thing) => {
  7533. apis.showAt(component, anchor, thing);
  7534. },
  7535. showWithin: (apis, component, anchor, thing, boxElement) => {
  7536. apis.showWithin(component, anchor, thing, boxElement);
  7537. },
  7538. showWithinBounds: (apis, component, anchor, thing, bounds) => {
  7539. apis.showWithinBounds(component, anchor, thing, bounds);
  7540. },
  7541. showMenuAt: (apis, component, anchor, menuSpec) => {
  7542. apis.showMenuAt(component, anchor, menuSpec);
  7543. },
  7544. showMenuWithinBounds: (apis, component, anchor, menuSpec, bounds) => {
  7545. apis.showMenuWithinBounds(component, anchor, menuSpec, bounds);
  7546. },
  7547. hide: (apis, component) => {
  7548. apis.hide(component);
  7549. },
  7550. isOpen: (apis, component) => apis.isOpen(component),
  7551. getContent: (apis, component) => apis.getContent(component),
  7552. setContent: (apis, component, thing) => {
  7553. apis.setContent(component, thing);
  7554. },
  7555. reposition: (apis, component) => {
  7556. apis.reposition(component);
  7557. }
  7558. }
  7559. });
  7560. var global$9 = tinymce.util.Tools.resolve('tinymce.util.Delay');
  7561. const factory$l = detail => {
  7562. const events = events$a(detail.action);
  7563. const tag = detail.dom.tag;
  7564. const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
  7565. const getModAttributes = () => {
  7566. if (tag === 'button') {
  7567. const type = lookupAttr('type').getOr('button');
  7568. const roleAttrs = lookupAttr('role').map(role => ({ role })).getOr({});
  7569. return {
  7570. type,
  7571. ...roleAttrs
  7572. };
  7573. } else {
  7574. const role = lookupAttr('role').getOr('button');
  7575. return { role };
  7576. }
  7577. };
  7578. return {
  7579. uid: detail.uid,
  7580. dom: detail.dom,
  7581. components: detail.components,
  7582. events,
  7583. behaviours: SketchBehaviours.augment(detail.buttonBehaviours, [
  7584. Focusing.config({}),
  7585. Keying.config({
  7586. mode: 'execution',
  7587. useSpace: true,
  7588. useEnter: true
  7589. })
  7590. ]),
  7591. domModification: { attributes: getModAttributes() },
  7592. eventOrder: detail.eventOrder
  7593. };
  7594. };
  7595. const Button = single({
  7596. name: 'Button',
  7597. factory: factory$l,
  7598. configFields: [
  7599. defaulted('uid', undefined),
  7600. required$1('dom'),
  7601. defaulted('components', []),
  7602. SketchBehaviours.field('buttonBehaviours', [
  7603. Focusing,
  7604. Keying
  7605. ]),
  7606. option$3('action'),
  7607. option$3('role'),
  7608. defaulted('eventOrder', {})
  7609. ]
  7610. });
  7611. const record = spec => {
  7612. const uid = isSketchSpec(spec) && hasNonNullableKey(spec, 'uid') ? spec.uid : generate$5('memento');
  7613. const get = anyInSystem => anyInSystem.getSystem().getByUid(uid).getOrDie();
  7614. const getOpt = anyInSystem => anyInSystem.getSystem().getByUid(uid).toOptional();
  7615. const asSpec = () => ({
  7616. ...spec,
  7617. uid
  7618. });
  7619. return {
  7620. get,
  7621. getOpt,
  7622. asSpec
  7623. };
  7624. };
  7625. var global$8 = tinymce.util.Tools.resolve('tinymce.util.I18n');
  7626. const rtlTransform = {
  7627. 'indent': true,
  7628. 'outdent': true,
  7629. 'table-insert-column-after': true,
  7630. 'table-insert-column-before': true,
  7631. 'paste-column-after': true,
  7632. 'paste-column-before': true,
  7633. 'unordered-list': true,
  7634. 'list-bull-circle': true,
  7635. 'list-bull-default': true,
  7636. 'list-bull-square': true
  7637. };
  7638. const defaultIconName = 'temporary-placeholder';
  7639. const defaultIcon = icons => () => get$g(icons, defaultIconName).getOr('!not found!');
  7640. const getIconName = (name, icons) => {
  7641. const lcName = name.toLowerCase();
  7642. if (global$8.isRtl()) {
  7643. const rtlName = ensureTrailing(lcName, '-rtl');
  7644. return has$2(icons, rtlName) ? rtlName : lcName;
  7645. } else {
  7646. return lcName;
  7647. }
  7648. };
  7649. const lookupIcon = (name, icons) => get$g(icons, getIconName(name, icons));
  7650. const get$2 = (name, iconProvider) => {
  7651. const icons = iconProvider();
  7652. return lookupIcon(name, icons).getOrThunk(defaultIcon(icons));
  7653. };
  7654. const getOr = (name, iconProvider, fallbackIcon) => {
  7655. const icons = iconProvider();
  7656. return lookupIcon(name, icons).or(fallbackIcon).getOrThunk(defaultIcon(icons));
  7657. };
  7658. const needsRtlTransform = iconName => global$8.isRtl() ? has$2(rtlTransform, iconName) : false;
  7659. const addFocusableBehaviour = () => config('add-focusable', [runOnAttached(comp => {
  7660. child(comp.element, 'svg').each(svg => set$9(svg, 'focusable', 'false'));
  7661. })]);
  7662. const renderIcon$2 = (spec, iconName, icons, fallbackIcon) => {
  7663. var _a, _b;
  7664. const rtlIconClasses = needsRtlTransform(iconName) ? ['tox-icon--flip'] : [];
  7665. const iconHtml = get$g(icons, getIconName(iconName, icons)).or(fallbackIcon).getOrThunk(defaultIcon(icons));
  7666. return {
  7667. dom: {
  7668. tag: spec.tag,
  7669. attributes: (_a = spec.attributes) !== null && _a !== void 0 ? _a : {},
  7670. classes: spec.classes.concat(rtlIconClasses),
  7671. innerHtml: iconHtml
  7672. },
  7673. behaviours: derive$1([
  7674. ...(_b = spec.behaviours) !== null && _b !== void 0 ? _b : [],
  7675. addFocusableBehaviour()
  7676. ])
  7677. };
  7678. };
  7679. const render$3 = (iconName, spec, iconProvider, fallbackIcon = Optional.none()) => renderIcon$2(spec, iconName, iconProvider(), fallbackIcon);
  7680. const renderFirst = (iconNames, spec, iconProvider) => {
  7681. const icons = iconProvider();
  7682. const iconName = find$5(iconNames, name => has$2(icons, getIconName(name, icons)));
  7683. return renderIcon$2(spec, iconName.getOr(defaultIconName), icons, Optional.none());
  7684. };
  7685. const notificationIconMap = {
  7686. success: 'checkmark',
  7687. error: 'warning',
  7688. err: 'error',
  7689. warning: 'warning',
  7690. warn: 'warning',
  7691. info: 'info'
  7692. };
  7693. const factory$k = detail => {
  7694. const memBannerText = record({
  7695. dom: {
  7696. tag: 'p',
  7697. innerHtml: detail.translationProvider(detail.text)
  7698. },
  7699. behaviours: derive$1([Replacing.config({})])
  7700. });
  7701. const renderPercentBar = percent => ({
  7702. dom: {
  7703. tag: 'div',
  7704. classes: ['tox-bar'],
  7705. styles: { width: `${ percent }%` }
  7706. }
  7707. });
  7708. const renderPercentText = percent => ({
  7709. dom: {
  7710. tag: 'div',
  7711. classes: ['tox-text'],
  7712. innerHtml: `${ percent }%`
  7713. }
  7714. });
  7715. const memBannerProgress = record({
  7716. dom: {
  7717. tag: 'div',
  7718. classes: detail.progress ? [
  7719. 'tox-progress-bar',
  7720. 'tox-progress-indicator'
  7721. ] : ['tox-progress-bar']
  7722. },
  7723. components: [
  7724. {
  7725. dom: {
  7726. tag: 'div',
  7727. classes: ['tox-bar-container']
  7728. },
  7729. components: [renderPercentBar(0)]
  7730. },
  7731. renderPercentText(0)
  7732. ],
  7733. behaviours: derive$1([Replacing.config({})])
  7734. });
  7735. const updateProgress = (comp, percent) => {
  7736. if (comp.getSystem().isConnected()) {
  7737. memBannerProgress.getOpt(comp).each(progress => {
  7738. Replacing.set(progress, [
  7739. {
  7740. dom: {
  7741. tag: 'div',
  7742. classes: ['tox-bar-container']
  7743. },
  7744. components: [renderPercentBar(percent)]
  7745. },
  7746. renderPercentText(percent)
  7747. ]);
  7748. });
  7749. }
  7750. };
  7751. const updateText = (comp, text) => {
  7752. if (comp.getSystem().isConnected()) {
  7753. const banner = memBannerText.get(comp);
  7754. Replacing.set(banner, [text$1(text)]);
  7755. }
  7756. };
  7757. const apis = {
  7758. updateProgress,
  7759. updateText
  7760. };
  7761. const iconChoices = flatten([
  7762. detail.icon.toArray(),
  7763. detail.level.toArray(),
  7764. detail.level.bind(level => Optional.from(notificationIconMap[level])).toArray()
  7765. ]);
  7766. const memButton = record(Button.sketch({
  7767. dom: {
  7768. tag: 'button',
  7769. classes: [
  7770. 'tox-notification__dismiss',
  7771. 'tox-button',
  7772. 'tox-button--naked',
  7773. 'tox-button--icon'
  7774. ]
  7775. },
  7776. components: [render$3('close', {
  7777. tag: 'div',
  7778. classes: ['tox-icon'],
  7779. attributes: { 'aria-label': detail.translationProvider('Close') }
  7780. }, detail.iconProvider)],
  7781. action: comp => {
  7782. detail.onAction(comp);
  7783. }
  7784. }));
  7785. const notificationIconSpec = renderFirst(iconChoices, {
  7786. tag: 'div',
  7787. classes: ['tox-notification__icon']
  7788. }, detail.iconProvider);
  7789. const notificationBodySpec = {
  7790. dom: {
  7791. tag: 'div',
  7792. classes: ['tox-notification__body']
  7793. },
  7794. components: [memBannerText.asSpec()],
  7795. behaviours: derive$1([Replacing.config({})])
  7796. };
  7797. const components = [
  7798. notificationIconSpec,
  7799. notificationBodySpec
  7800. ];
  7801. return {
  7802. uid: detail.uid,
  7803. dom: {
  7804. tag: 'div',
  7805. attributes: { role: 'alert' },
  7806. classes: detail.level.map(level => [
  7807. 'tox-notification',
  7808. 'tox-notification--in',
  7809. `tox-notification--${ level }`
  7810. ]).getOr([
  7811. 'tox-notification',
  7812. 'tox-notification--in'
  7813. ])
  7814. },
  7815. behaviours: derive$1([
  7816. Focusing.config({}),
  7817. config('notification-events', [run$1(focusin(), comp => {
  7818. memButton.getOpt(comp).each(Focusing.focus);
  7819. })])
  7820. ]),
  7821. components: components.concat(detail.progress ? [memBannerProgress.asSpec()] : []).concat(!detail.closeButton ? [] : [memButton.asSpec()]),
  7822. apis
  7823. };
  7824. };
  7825. const Notification = single({
  7826. name: 'Notification',
  7827. factory: factory$k,
  7828. configFields: [
  7829. option$3('level'),
  7830. required$1('progress'),
  7831. required$1('icon'),
  7832. required$1('onAction'),
  7833. required$1('text'),
  7834. required$1('iconProvider'),
  7835. required$1('translationProvider'),
  7836. defaultedBoolean('closeButton', true)
  7837. ],
  7838. apis: {
  7839. updateProgress: (apis, comp, percent) => {
  7840. apis.updateProgress(comp, percent);
  7841. },
  7842. updateText: (apis, comp, text) => {
  7843. apis.updateText(comp, text);
  7844. }
  7845. }
  7846. });
  7847. var NotificationManagerImpl = (editor, extras, uiMothership) => {
  7848. const sharedBackstage = extras.backstage.shared;
  7849. const getBounds = () => {
  7850. const contentArea = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
  7851. const win$1 = win();
  7852. const x = clamp(win$1.x, contentArea.x, contentArea.right);
  7853. const y = clamp(win$1.y, contentArea.y, contentArea.bottom);
  7854. const right = Math.max(contentArea.right, win$1.right);
  7855. const bottom = Math.max(contentArea.bottom, win$1.bottom);
  7856. return Optional.some(bounds(x, y, right - x, bottom - y));
  7857. };
  7858. const open = (settings, closeCallback) => {
  7859. const close = () => {
  7860. closeCallback();
  7861. InlineView.hide(notificationWrapper);
  7862. };
  7863. const notification = build$1(Notification.sketch({
  7864. text: settings.text,
  7865. level: contains$2([
  7866. 'success',
  7867. 'error',
  7868. 'warning',
  7869. 'warn',
  7870. 'info'
  7871. ], settings.type) ? settings.type : undefined,
  7872. progress: settings.progressBar === true,
  7873. icon: Optional.from(settings.icon),
  7874. closeButton: settings.closeButton,
  7875. onAction: close,
  7876. iconProvider: sharedBackstage.providers.icons,
  7877. translationProvider: sharedBackstage.providers.translate
  7878. }));
  7879. const notificationWrapper = build$1(InlineView.sketch({
  7880. dom: {
  7881. tag: 'div',
  7882. classes: ['tox-notifications-container']
  7883. },
  7884. lazySink: sharedBackstage.getSink,
  7885. fireDismissalEventInstead: {},
  7886. ...sharedBackstage.header.isPositionedAtTop() ? {} : { fireRepositionEventInstead: {} }
  7887. }));
  7888. uiMothership.add(notificationWrapper);
  7889. if (settings.timeout > 0) {
  7890. global$9.setEditorTimeout(editor, () => {
  7891. close();
  7892. }, settings.timeout);
  7893. }
  7894. const reposition = () => {
  7895. const notificationSpec = premade(notification);
  7896. const anchorOverrides = { maxHeightFunction: expandable$1() };
  7897. const allNotifications = editor.notificationManager.getNotifications();
  7898. if (allNotifications[0] === thisNotification) {
  7899. const anchor = {
  7900. ...sharedBackstage.anchors.banner(),
  7901. overrides: anchorOverrides
  7902. };
  7903. InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor }, getBounds);
  7904. } else {
  7905. indexOf(allNotifications, thisNotification).each(idx => {
  7906. const previousNotification = allNotifications[idx - 1].getEl();
  7907. const nodeAnchor = {
  7908. type: 'node',
  7909. root: body(),
  7910. node: Optional.some(SugarElement.fromDom(previousNotification)),
  7911. overrides: anchorOverrides,
  7912. layouts: {
  7913. onRtl: () => [south$2],
  7914. onLtr: () => [south$2]
  7915. }
  7916. };
  7917. InlineView.showWithinBounds(notificationWrapper, notificationSpec, { anchor: nodeAnchor }, getBounds);
  7918. });
  7919. }
  7920. };
  7921. const thisNotification = {
  7922. close,
  7923. reposition,
  7924. text: nuText => {
  7925. Notification.updateText(notification, nuText);
  7926. },
  7927. settings,
  7928. getEl: () => notification.element.dom,
  7929. progressBar: {
  7930. value: percent => {
  7931. Notification.updateProgress(notification, percent);
  7932. }
  7933. }
  7934. };
  7935. return thisNotification;
  7936. };
  7937. const close = notification => {
  7938. notification.close();
  7939. };
  7940. const getArgs = notification => {
  7941. return notification.settings;
  7942. };
  7943. return {
  7944. open,
  7945. close,
  7946. getArgs
  7947. };
  7948. };
  7949. var global$7 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  7950. var global$6 = tinymce.util.Tools.resolve('tinymce.EditorManager');
  7951. var global$5 = tinymce.util.Tools.resolve('tinymce.Env');
  7952. var ToolbarMode$1;
  7953. (function (ToolbarMode) {
  7954. ToolbarMode['default'] = 'wrap';
  7955. ToolbarMode['floating'] = 'floating';
  7956. ToolbarMode['sliding'] = 'sliding';
  7957. ToolbarMode['scrolling'] = 'scrolling';
  7958. }(ToolbarMode$1 || (ToolbarMode$1 = {})));
  7959. var ToolbarLocation$1;
  7960. (function (ToolbarLocation) {
  7961. ToolbarLocation['auto'] = 'auto';
  7962. ToolbarLocation['top'] = 'top';
  7963. ToolbarLocation['bottom'] = 'bottom';
  7964. }(ToolbarLocation$1 || (ToolbarLocation$1 = {})));
  7965. const option$2 = name => editor => editor.options.get(name);
  7966. const wrapOptional = fn => editor => Optional.from(fn(editor));
  7967. const register$e = editor => {
  7968. const isPhone = global$5.deviceType.isPhone();
  7969. const isMobile = global$5.deviceType.isTablet() || isPhone;
  7970. const registerOption = editor.options.register;
  7971. const stringOrFalseProcessor = value => isString(value) || value === false;
  7972. const stringOrNumberProcessor = value => isString(value) || isNumber(value);
  7973. registerOption('skin', {
  7974. processor: value => isString(value) || value === false,
  7975. default: 'oxide'
  7976. });
  7977. registerOption('skin_url', { processor: 'string' });
  7978. registerOption('height', {
  7979. processor: stringOrNumberProcessor,
  7980. default: Math.max(editor.getElement().offsetHeight, 400)
  7981. });
  7982. registerOption('width', {
  7983. processor: stringOrNumberProcessor,
  7984. default: global$7.DOM.getStyle(editor.getElement(), 'width')
  7985. });
  7986. registerOption('min_height', {
  7987. processor: 'number',
  7988. default: 100
  7989. });
  7990. registerOption('min_width', { processor: 'number' });
  7991. registerOption('max_height', { processor: 'number' });
  7992. registerOption('max_width', { processor: 'number' });
  7993. registerOption('style_formats', { processor: 'object[]' });
  7994. registerOption('style_formats_merge', {
  7995. processor: 'boolean',
  7996. default: false
  7997. });
  7998. registerOption('style_formats_autohide', {
  7999. processor: 'boolean',
  8000. default: false
  8001. });
  8002. registerOption('line_height_formats', {
  8003. processor: 'string',
  8004. default: '1 1.1 1.2 1.3 1.4 1.5 2'
  8005. });
  8006. registerOption('font_family_formats', {
  8007. processor: 'string',
  8008. 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'
  8009. });
  8010. registerOption('font_size_formats', {
  8011. processor: 'string',
  8012. default: '8pt 10pt 12pt 14pt 18pt 24pt 36pt'
  8013. });
  8014. registerOption('block_formats', {
  8015. processor: 'string',
  8016. default: 'Paragraph=p;' + 'Heading 1=h1;' + 'Heading 2=h2;' + 'Heading 3=h3;' + 'Heading 4=h4;' + 'Heading 5=h5;' + 'Heading 6=h6;' + 'Preformatted=pre'
  8017. });
  8018. registerOption('content_langs', { processor: 'object[]' });
  8019. registerOption('removed_menuitems', {
  8020. processor: 'string',
  8021. default: ''
  8022. });
  8023. registerOption('menubar', {
  8024. processor: value => isString(value) || isBoolean(value),
  8025. default: !isPhone
  8026. });
  8027. registerOption('menu', {
  8028. processor: 'object',
  8029. default: {}
  8030. });
  8031. registerOption('toolbar', {
  8032. processor: value => {
  8033. if (isBoolean(value) || isString(value) || isArray(value)) {
  8034. return {
  8035. value,
  8036. valid: true
  8037. };
  8038. } else {
  8039. return {
  8040. valid: false,
  8041. message: 'Must be a boolean, string or array.'
  8042. };
  8043. }
  8044. },
  8045. default: true
  8046. });
  8047. range$2(9, num => {
  8048. registerOption('toolbar' + (num + 1), { processor: 'string' });
  8049. });
  8050. registerOption('toolbar_mode', {
  8051. processor: 'string',
  8052. default: isMobile ? 'scrolling' : 'floating'
  8053. });
  8054. registerOption('toolbar_groups', {
  8055. processor: 'object',
  8056. default: {}
  8057. });
  8058. registerOption('toolbar_location', {
  8059. processor: 'string',
  8060. default: ToolbarLocation$1.auto
  8061. });
  8062. registerOption('toolbar_persist', {
  8063. processor: 'boolean',
  8064. default: false
  8065. });
  8066. registerOption('toolbar_sticky', {
  8067. processor: 'boolean',
  8068. default: editor.inline
  8069. });
  8070. registerOption('toolbar_sticky_offset', {
  8071. processor: 'number',
  8072. default: 0
  8073. });
  8074. registerOption('fixed_toolbar_container', {
  8075. processor: 'string',
  8076. default: ''
  8077. });
  8078. registerOption('fixed_toolbar_container_target', { processor: 'object' });
  8079. registerOption('file_picker_callback', { processor: 'function' });
  8080. registerOption('file_picker_validator_handler', { processor: 'function' });
  8081. registerOption('file_picker_types', { processor: 'string' });
  8082. registerOption('typeahead_urls', {
  8083. processor: 'boolean',
  8084. default: true
  8085. });
  8086. registerOption('anchor_top', {
  8087. processor: stringOrFalseProcessor,
  8088. default: '#top'
  8089. });
  8090. registerOption('anchor_bottom', {
  8091. processor: stringOrFalseProcessor,
  8092. default: '#bottom'
  8093. });
  8094. registerOption('draggable_modal', {
  8095. processor: 'boolean',
  8096. default: false
  8097. });
  8098. registerOption('statusbar', {
  8099. processor: 'boolean',
  8100. default: true
  8101. });
  8102. registerOption('elementpath', {
  8103. processor: 'boolean',
  8104. default: true
  8105. });
  8106. registerOption('branding', {
  8107. processor: 'boolean',
  8108. default: true
  8109. });
  8110. registerOption('resize', {
  8111. processor: value => value === 'both' || isBoolean(value),
  8112. default: !global$5.deviceType.isTouch()
  8113. });
  8114. registerOption('sidebar_show', { processor: 'string' });
  8115. };
  8116. const isReadOnly = option$2('readonly');
  8117. const getHeightOption = option$2('height');
  8118. const getWidthOption = option$2('width');
  8119. const getMinWidthOption = wrapOptional(option$2('min_width'));
  8120. const getMinHeightOption = wrapOptional(option$2('min_height'));
  8121. const getMaxWidthOption = wrapOptional(option$2('max_width'));
  8122. const getMaxHeightOption = wrapOptional(option$2('max_height'));
  8123. const getUserStyleFormats = wrapOptional(option$2('style_formats'));
  8124. const shouldMergeStyleFormats = option$2('style_formats_merge');
  8125. const shouldAutoHideStyleFormats = option$2('style_formats_autohide');
  8126. const getContentLanguages = option$2('content_langs');
  8127. const getRemovedMenuItems = option$2('removed_menuitems');
  8128. const getToolbarMode = option$2('toolbar_mode');
  8129. const getToolbarGroups = option$2('toolbar_groups');
  8130. const getToolbarLocation = option$2('toolbar_location');
  8131. const fixedContainerSelector = option$2('fixed_toolbar_container');
  8132. const fixedToolbarContainerTarget = option$2('fixed_toolbar_container_target');
  8133. const isToolbarPersist = option$2('toolbar_persist');
  8134. const getStickyToolbarOffset = option$2('toolbar_sticky_offset');
  8135. const getMenubar = option$2('menubar');
  8136. const getToolbar = option$2('toolbar');
  8137. const getFilePickerCallback = option$2('file_picker_callback');
  8138. const getFilePickerValidatorHandler = option$2('file_picker_validator_handler');
  8139. const getFilePickerTypes = option$2('file_picker_types');
  8140. const useTypeaheadUrls = option$2('typeahead_urls');
  8141. const getAnchorTop = option$2('anchor_top');
  8142. const getAnchorBottom = option$2('anchor_bottom');
  8143. const isDraggableModal$1 = option$2('draggable_modal');
  8144. const useStatusBar = option$2('statusbar');
  8145. const useElementPath = option$2('elementpath');
  8146. const useBranding = option$2('branding');
  8147. const getResize = option$2('resize');
  8148. const getPasteAsText = option$2('paste_as_text');
  8149. const getSidebarShow = option$2('sidebar_show');
  8150. const isSkinDisabled = editor => editor.options.get('skin') === false;
  8151. const isMenubarEnabled = editor => editor.options.get('menubar') !== false;
  8152. const getSkinUrl = editor => {
  8153. const skinUrl = editor.options.get('skin_url');
  8154. if (isSkinDisabled(editor)) {
  8155. return skinUrl;
  8156. } else {
  8157. if (skinUrl) {
  8158. return editor.documentBaseURI.toAbsolute(skinUrl);
  8159. } else {
  8160. const skin = editor.options.get('skin');
  8161. return global$6.baseURL + '/skins/ui/' + skin;
  8162. }
  8163. }
  8164. };
  8165. const getLineHeightFormats = editor => editor.options.get('line_height_formats').split(' ');
  8166. const isToolbarEnabled = editor => {
  8167. const toolbar = getToolbar(editor);
  8168. const isToolbarString = isString(toolbar);
  8169. const isToolbarObjectArray = isArray(toolbar) && toolbar.length > 0;
  8170. return !isMultipleToolbars(editor) && (isToolbarObjectArray || isToolbarString || toolbar === true);
  8171. };
  8172. const getMultipleToolbarsOption = editor => {
  8173. const toolbars = range$2(9, num => editor.options.get('toolbar' + (num + 1)));
  8174. const toolbarArray = filter$2(toolbars, isString);
  8175. return someIf(toolbarArray.length > 0, toolbarArray);
  8176. };
  8177. const isMultipleToolbars = editor => getMultipleToolbarsOption(editor).fold(() => {
  8178. const toolbar = getToolbar(editor);
  8179. return isArrayOf(toolbar, isString) && toolbar.length > 0;
  8180. }, always);
  8181. const isToolbarLocationBottom = editor => getToolbarLocation(editor) === ToolbarLocation$1.bottom;
  8182. const fixedContainerTarget = editor => {
  8183. if (!editor.inline) {
  8184. return Optional.none();
  8185. }
  8186. const selector = fixedContainerSelector(editor);
  8187. if (selector.length > 0) {
  8188. return descendant(body(), selector);
  8189. }
  8190. const element = fixedToolbarContainerTarget(editor);
  8191. if (isNonNullable(element)) {
  8192. return Optional.some(SugarElement.fromDom(element));
  8193. }
  8194. return Optional.none();
  8195. };
  8196. const useFixedContainer = editor => editor.inline && fixedContainerTarget(editor).isSome();
  8197. const getUiContainer = editor => {
  8198. const fixedContainer = fixedContainerTarget(editor);
  8199. return fixedContainer.getOrThunk(() => getContentContainer(getRootNode(SugarElement.fromDom(editor.getElement()))));
  8200. };
  8201. const isDistractionFree = editor => editor.inline && !isMenubarEnabled(editor) && !isToolbarEnabled(editor) && !isMultipleToolbars(editor);
  8202. const isStickyToolbar = editor => {
  8203. const isStickyToolbar = editor.options.get('toolbar_sticky');
  8204. return (isStickyToolbar || editor.inline) && !useFixedContainer(editor) && !isDistractionFree(editor);
  8205. };
  8206. const getMenus = editor => {
  8207. const menu = editor.options.get('menu');
  8208. return map$1(menu, menu => ({
  8209. ...menu,
  8210. items: menu.items
  8211. }));
  8212. };
  8213. var Options = /*#__PURE__*/Object.freeze({
  8214. __proto__: null,
  8215. get ToolbarMode () { return ToolbarMode$1; },
  8216. get ToolbarLocation () { return ToolbarLocation$1; },
  8217. register: register$e,
  8218. getSkinUrl: getSkinUrl,
  8219. isReadOnly: isReadOnly,
  8220. isSkinDisabled: isSkinDisabled,
  8221. getHeightOption: getHeightOption,
  8222. getWidthOption: getWidthOption,
  8223. getMinWidthOption: getMinWidthOption,
  8224. getMinHeightOption: getMinHeightOption,
  8225. getMaxWidthOption: getMaxWidthOption,
  8226. getMaxHeightOption: getMaxHeightOption,
  8227. getUserStyleFormats: getUserStyleFormats,
  8228. shouldMergeStyleFormats: shouldMergeStyleFormats,
  8229. shouldAutoHideStyleFormats: shouldAutoHideStyleFormats,
  8230. getLineHeightFormats: getLineHeightFormats,
  8231. getContentLanguages: getContentLanguages,
  8232. getRemovedMenuItems: getRemovedMenuItems,
  8233. isMenubarEnabled: isMenubarEnabled,
  8234. isMultipleToolbars: isMultipleToolbars,
  8235. isToolbarEnabled: isToolbarEnabled,
  8236. isToolbarPersist: isToolbarPersist,
  8237. getMultipleToolbarsOption: getMultipleToolbarsOption,
  8238. getUiContainer: getUiContainer,
  8239. useFixedContainer: useFixedContainer,
  8240. getToolbarMode: getToolbarMode,
  8241. isDraggableModal: isDraggableModal$1,
  8242. isDistractionFree: isDistractionFree,
  8243. isStickyToolbar: isStickyToolbar,
  8244. getStickyToolbarOffset: getStickyToolbarOffset,
  8245. getToolbarLocation: getToolbarLocation,
  8246. isToolbarLocationBottom: isToolbarLocationBottom,
  8247. getToolbarGroups: getToolbarGroups,
  8248. getMenus: getMenus,
  8249. getMenubar: getMenubar,
  8250. getToolbar: getToolbar,
  8251. getFilePickerCallback: getFilePickerCallback,
  8252. getFilePickerTypes: getFilePickerTypes,
  8253. useTypeaheadUrls: useTypeaheadUrls,
  8254. getAnchorTop: getAnchorTop,
  8255. getAnchorBottom: getAnchorBottom,
  8256. getFilePickerValidatorHandler: getFilePickerValidatorHandler,
  8257. useStatusBar: useStatusBar,
  8258. useElementPath: useElementPath,
  8259. useBranding: useBranding,
  8260. getResize: getResize,
  8261. getPasteAsText: getPasteAsText,
  8262. getSidebarShow: getSidebarShow
  8263. });
  8264. const autocompleteSelector = '[data-mce-autocompleter]';
  8265. const detect = elm => closest$1(elm, autocompleteSelector);
  8266. const findIn = elm => descendant(elm, autocompleteSelector);
  8267. const setup$e = (api, editor) => {
  8268. const redirectKeyToItem = (item, e) => {
  8269. emitWith(item, keydown(), { raw: e });
  8270. };
  8271. const getItem = () => api.getMenu().bind(Highlighting.getHighlighted);
  8272. editor.on('keydown', e => {
  8273. const keyCode = e.which;
  8274. if (!api.isActive()) {
  8275. return;
  8276. }
  8277. if (api.isMenuOpen()) {
  8278. if (keyCode === 13) {
  8279. getItem().each(emitExecute);
  8280. e.preventDefault();
  8281. } else if (keyCode === 40) {
  8282. getItem().fold(() => {
  8283. api.getMenu().each(Highlighting.highlightFirst);
  8284. }, item => {
  8285. redirectKeyToItem(item, e);
  8286. });
  8287. e.preventDefault();
  8288. e.stopImmediatePropagation();
  8289. } else if (keyCode === 37 || keyCode === 38 || keyCode === 39) {
  8290. getItem().each(item => {
  8291. redirectKeyToItem(item, e);
  8292. e.preventDefault();
  8293. e.stopImmediatePropagation();
  8294. });
  8295. }
  8296. } else {
  8297. if (keyCode === 13 || keyCode === 38 || keyCode === 40) {
  8298. api.cancelIfNecessary();
  8299. }
  8300. }
  8301. });
  8302. editor.on('NodeChange', e => {
  8303. if (api.isActive() && !api.isProcessingAction() && detect(SugarElement.fromDom(e.element)).isNone()) {
  8304. api.cancelIfNecessary();
  8305. }
  8306. });
  8307. };
  8308. const AutocompleterEditorEvents = { setup: setup$e };
  8309. var ItemResponse;
  8310. (function (ItemResponse) {
  8311. ItemResponse[ItemResponse['CLOSE_ON_EXECUTE'] = 0] = 'CLOSE_ON_EXECUTE';
  8312. ItemResponse[ItemResponse['BUBBLE_TO_SANDBOX'] = 1] = 'BUBBLE_TO_SANDBOX';
  8313. }(ItemResponse || (ItemResponse = {})));
  8314. var ItemResponse$1 = ItemResponse;
  8315. const navClass = 'tox-menu-nav__js';
  8316. const selectableClass = 'tox-collection__item';
  8317. const colorClass = 'tox-swatch';
  8318. const presetClasses = {
  8319. normal: navClass,
  8320. color: colorClass
  8321. };
  8322. const tickedClass = 'tox-collection__item--enabled';
  8323. const groupHeadingClass = 'tox-collection__group-heading';
  8324. const iconClass = 'tox-collection__item-icon';
  8325. const textClass = 'tox-collection__item-label';
  8326. const accessoryClass = 'tox-collection__item-accessory';
  8327. const caretClass = 'tox-collection__item-caret';
  8328. const checkmarkClass = 'tox-collection__item-checkmark';
  8329. const activeClass = 'tox-collection__item--active';
  8330. const containerClass = 'tox-collection__item-container';
  8331. const containerColumnClass = 'tox-collection__item-container--column';
  8332. const containerRowClass = 'tox-collection__item-container--row';
  8333. const containerAlignRightClass = 'tox-collection__item-container--align-right';
  8334. const containerAlignLeftClass = 'tox-collection__item-container--align-left';
  8335. const containerValignTopClass = 'tox-collection__item-container--valign-top';
  8336. const containerValignMiddleClass = 'tox-collection__item-container--valign-middle';
  8337. const containerValignBottomClass = 'tox-collection__item-container--valign-bottom';
  8338. const classForPreset = presets => get$g(presetClasses, presets).getOr(navClass);
  8339. const forMenu = presets => {
  8340. if (presets === 'color') {
  8341. return 'tox-swatches';
  8342. } else {
  8343. return 'tox-menu';
  8344. }
  8345. };
  8346. const classes = presets => ({
  8347. backgroundMenu: 'tox-background-menu',
  8348. selectedMenu: 'tox-selected-menu',
  8349. selectedItem: 'tox-collection__item--active',
  8350. hasIcons: 'tox-menu--has-icons',
  8351. menu: forMenu(presets),
  8352. tieredMenu: 'tox-tiered-menu'
  8353. });
  8354. const markers = presets => {
  8355. const menuClasses = classes(presets);
  8356. return {
  8357. backgroundMenu: menuClasses.backgroundMenu,
  8358. selectedMenu: menuClasses.selectedMenu,
  8359. menu: menuClasses.menu,
  8360. selectedItem: menuClasses.selectedItem,
  8361. item: classForPreset(presets)
  8362. };
  8363. };
  8364. const dom$1 = (hasIcons, columns, presets) => {
  8365. const menuClasses = classes(presets);
  8366. return {
  8367. tag: 'div',
  8368. classes: flatten([
  8369. [
  8370. menuClasses.menu,
  8371. `tox-menu-${ columns }-column`
  8372. ],
  8373. hasIcons ? [menuClasses.hasIcons] : []
  8374. ])
  8375. };
  8376. };
  8377. const components = [Menu.parts.items({})];
  8378. const part = (hasIcons, columns, presets) => {
  8379. const menuClasses = classes(presets);
  8380. const d = {
  8381. tag: 'div',
  8382. classes: flatten([[menuClasses.tieredMenu]])
  8383. };
  8384. return {
  8385. dom: d,
  8386. markers: markers(presets)
  8387. };
  8388. };
  8389. const chunk = (rowDom, numColumns) => items => {
  8390. const chunks = chunk$1(items, numColumns);
  8391. return map$2(chunks, c => ({
  8392. dom: rowDom,
  8393. components: c
  8394. }));
  8395. };
  8396. const forSwatch = columns => ({
  8397. dom: {
  8398. tag: 'div',
  8399. classes: [
  8400. 'tox-menu',
  8401. 'tox-swatches-menu'
  8402. ]
  8403. },
  8404. components: [{
  8405. dom: {
  8406. tag: 'div',
  8407. classes: ['tox-swatches']
  8408. },
  8409. components: [Menu.parts.items({
  8410. preprocess: columns !== 'auto' ? chunk({
  8411. tag: 'div',
  8412. classes: ['tox-swatches__row']
  8413. }, columns) : identity
  8414. })]
  8415. }]
  8416. });
  8417. const forToolbar = columns => ({
  8418. dom: {
  8419. tag: 'div',
  8420. classes: [
  8421. 'tox-menu',
  8422. 'tox-collection',
  8423. 'tox-collection--toolbar',
  8424. 'tox-collection--toolbar-lg'
  8425. ]
  8426. },
  8427. components: [Menu.parts.items({
  8428. preprocess: chunk({
  8429. tag: 'div',
  8430. classes: ['tox-collection__group']
  8431. }, columns)
  8432. })]
  8433. });
  8434. const preprocessCollection = (items, isSeparator) => {
  8435. const allSplits = [];
  8436. let currentSplit = [];
  8437. each$1(items, (item, i) => {
  8438. if (isSeparator(item, i)) {
  8439. if (currentSplit.length > 0) {
  8440. allSplits.push(currentSplit);
  8441. }
  8442. currentSplit = [];
  8443. if (has$2(item.dom, 'innerHtml') || item.components.length > 0) {
  8444. currentSplit.push(item);
  8445. }
  8446. } else {
  8447. currentSplit.push(item);
  8448. }
  8449. });
  8450. if (currentSplit.length > 0) {
  8451. allSplits.push(currentSplit);
  8452. }
  8453. return map$2(allSplits, s => ({
  8454. dom: {
  8455. tag: 'div',
  8456. classes: ['tox-collection__group']
  8457. },
  8458. components: s
  8459. }));
  8460. };
  8461. const forCollection = (columns, initItems, _hasIcons = true) => ({
  8462. dom: {
  8463. tag: 'div',
  8464. classes: [
  8465. 'tox-menu',
  8466. 'tox-collection'
  8467. ].concat(columns === 1 ? ['tox-collection--list'] : ['tox-collection--grid'])
  8468. },
  8469. components: [Menu.parts.items({
  8470. preprocess: items => {
  8471. if (columns !== 'auto' && columns > 1) {
  8472. return chunk({
  8473. tag: 'div',
  8474. classes: ['tox-collection__group']
  8475. }, columns)(items);
  8476. } else {
  8477. return preprocessCollection(items, (_item, i) => initItems[i].type === 'separator');
  8478. }
  8479. }
  8480. })]
  8481. });
  8482. const forHorizontalCollection = (initItems, _hasIcons = true) => ({
  8483. dom: {
  8484. tag: 'div',
  8485. classes: [
  8486. 'tox-collection',
  8487. 'tox-collection--horizontal'
  8488. ]
  8489. },
  8490. components: [Menu.parts.items({ preprocess: items => preprocessCollection(items, (_item, i) => initItems[i].type === 'separator') })]
  8491. });
  8492. const menuHasIcons = xs => exists(xs, item => 'icon' in item && item.icon !== undefined);
  8493. const handleError = error => {
  8494. console.error(formatError(error));
  8495. console.log(error);
  8496. return Optional.none();
  8497. };
  8498. const createHorizontalPartialMenuWithAlloyItems = (value, _hasIcons, items, _columns, _presets) => {
  8499. const structure = forHorizontalCollection(items);
  8500. return {
  8501. value,
  8502. dom: structure.dom,
  8503. components: structure.components,
  8504. items
  8505. };
  8506. };
  8507. const createPartialMenuWithAlloyItems = (value, hasIcons, items, columns, presets) => {
  8508. if (presets === 'color') {
  8509. const structure = forSwatch(columns);
  8510. return {
  8511. value,
  8512. dom: structure.dom,
  8513. components: structure.components,
  8514. items
  8515. };
  8516. }
  8517. if (presets === 'normal' && columns === 'auto') {
  8518. const structure = forCollection(columns, items);
  8519. return {
  8520. value,
  8521. dom: structure.dom,
  8522. components: structure.components,
  8523. items
  8524. };
  8525. }
  8526. if (presets === 'normal' && columns === 1) {
  8527. const structure = forCollection(1, items);
  8528. return {
  8529. value,
  8530. dom: structure.dom,
  8531. components: structure.components,
  8532. items
  8533. };
  8534. }
  8535. if (presets === 'normal') {
  8536. const structure = forCollection(columns, items);
  8537. return {
  8538. value,
  8539. dom: structure.dom,
  8540. components: structure.components,
  8541. items
  8542. };
  8543. }
  8544. if (presets === 'listpreview' && columns !== 'auto') {
  8545. const structure = forToolbar(columns);
  8546. return {
  8547. value,
  8548. dom: structure.dom,
  8549. components: structure.components,
  8550. items
  8551. };
  8552. }
  8553. return {
  8554. value,
  8555. dom: dom$1(hasIcons, columns, presets),
  8556. components: components,
  8557. items
  8558. };
  8559. };
  8560. const type = requiredString('type');
  8561. const name$1 = requiredString('name');
  8562. const label = requiredString('label');
  8563. const text = requiredString('text');
  8564. const title = requiredString('title');
  8565. const icon = requiredString('icon');
  8566. const value$1 = requiredString('value');
  8567. const fetch$1 = requiredFunction('fetch');
  8568. const getSubmenuItems = requiredFunction('getSubmenuItems');
  8569. const onAction = requiredFunction('onAction');
  8570. const onItemAction = requiredFunction('onItemAction');
  8571. const onSetup = defaultedFunction('onSetup', () => noop);
  8572. const optionalName = optionString('name');
  8573. const optionalText = optionString('text');
  8574. const optionalIcon = optionString('icon');
  8575. const optionalTooltip = optionString('tooltip');
  8576. const optionalLabel = optionString('label');
  8577. const optionalShortcut = optionString('shortcut');
  8578. const optionalSelect = optionFunction('select');
  8579. const active = defaultedBoolean('active', false);
  8580. const borderless = defaultedBoolean('borderless', false);
  8581. const enabled = defaultedBoolean('enabled', true);
  8582. const primary = defaultedBoolean('primary', false);
  8583. const defaultedColumns = num => defaulted('columns', num);
  8584. const defaultedMeta = defaulted('meta', {});
  8585. const defaultedOnAction = defaultedFunction('onAction', noop);
  8586. const defaultedType = type => defaultedString('type', type);
  8587. const generatedName = namePrefix => field$1('name', 'name', defaultedThunk(() => generate$6(`${ namePrefix }-name`)), string);
  8588. const generatedValue = valuePrefix => field$1('value', 'value', defaultedThunk(() => generate$6(`${ valuePrefix }-value`)), anyValue());
  8589. const separatorMenuItemSchema = objOf([
  8590. type,
  8591. optionalText
  8592. ]);
  8593. const createSeparatorMenuItem = spec => asRaw('separatormenuitem', separatorMenuItemSchema, spec);
  8594. const autocompleterItemSchema = objOf([
  8595. defaultedType('autocompleteitem'),
  8596. active,
  8597. enabled,
  8598. defaultedMeta,
  8599. value$1,
  8600. optionalText,
  8601. optionalIcon
  8602. ]);
  8603. const createSeparatorItem = spec => asRaw('Autocompleter.Separator', separatorMenuItemSchema, spec);
  8604. const createAutocompleterItem = spec => asRaw('Autocompleter.Item', autocompleterItemSchema, spec);
  8605. const baseToolbarButtonFields = [
  8606. enabled,
  8607. optionalTooltip,
  8608. optionalIcon,
  8609. optionalText,
  8610. onSetup
  8611. ];
  8612. const toolbarButtonSchema = objOf([
  8613. type,
  8614. onAction
  8615. ].concat(baseToolbarButtonFields));
  8616. const createToolbarButton = spec => asRaw('toolbarbutton', toolbarButtonSchema, spec);
  8617. const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
  8618. const toggleButtonSchema = objOf(baseToolbarToggleButtonFields.concat([
  8619. type,
  8620. onAction
  8621. ]));
  8622. const createToggleButton = spec => asRaw('ToggleButton', toggleButtonSchema, spec);
  8623. const contextBarFields = [
  8624. defaultedFunction('predicate', never),
  8625. defaultedStringEnum('scope', 'node', [
  8626. 'node',
  8627. 'editor'
  8628. ]),
  8629. defaultedStringEnum('position', 'selection', [
  8630. 'node',
  8631. 'selection',
  8632. 'line'
  8633. ])
  8634. ];
  8635. const contextButtonFields = baseToolbarButtonFields.concat([
  8636. defaultedType('contextformbutton'),
  8637. primary,
  8638. onAction,
  8639. customField('original', identity)
  8640. ]);
  8641. const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
  8642. defaultedType('contextformbutton'),
  8643. primary,
  8644. onAction,
  8645. customField('original', identity)
  8646. ]);
  8647. const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
  8648. const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
  8649. const toggleOrNormal = choose$1('type', {
  8650. contextformbutton: contextButtonFields,
  8651. contextformtogglebutton: contextToggleButtonFields
  8652. });
  8653. const contextFormSchema = objOf([
  8654. defaultedType('contextform'),
  8655. defaultedFunction('initValue', constant$1('')),
  8656. optionalLabel,
  8657. requiredArrayOf('commands', toggleOrNormal),
  8658. optionOf('launch', choose$1('type', {
  8659. contextformbutton: launchButtonFields,
  8660. contextformtogglebutton: launchToggleButtonFields
  8661. }))
  8662. ].concat(contextBarFields));
  8663. const createContextForm = spec => asRaw('ContextForm', contextFormSchema, spec);
  8664. const contextToolbarSchema = objOf([
  8665. defaultedType('contexttoolbar'),
  8666. requiredString('items')
  8667. ].concat(contextBarFields));
  8668. const createContextToolbar = spec => asRaw('ContextToolbar', contextToolbarSchema, spec);
  8669. const cardImageFields = [
  8670. type,
  8671. requiredString('src'),
  8672. optionString('alt'),
  8673. defaultedArrayOf('classes', [], string)
  8674. ];
  8675. const cardImageSchema = objOf(cardImageFields);
  8676. const cardTextFields = [
  8677. type,
  8678. text,
  8679. optionalName,
  8680. defaultedArrayOf('classes', ['tox-collection__item-label'], string)
  8681. ];
  8682. const cardTextSchema = objOf(cardTextFields);
  8683. const itemSchema$1 = valueThunk(() => choose$2('type', {
  8684. cardimage: cardImageSchema,
  8685. cardtext: cardTextSchema,
  8686. cardcontainer: cardContainerSchema
  8687. }));
  8688. const cardContainerSchema = objOf([
  8689. type,
  8690. defaultedString('direction', 'horizontal'),
  8691. defaultedString('align', 'left'),
  8692. defaultedString('valign', 'middle'),
  8693. requiredArrayOf('items', itemSchema$1)
  8694. ]);
  8695. const commonMenuItemFields = [
  8696. enabled,
  8697. optionalText,
  8698. optionalShortcut,
  8699. generatedValue('menuitem'),
  8700. defaultedMeta
  8701. ];
  8702. const cardMenuItemSchema = objOf([
  8703. type,
  8704. optionalLabel,
  8705. requiredArrayOf('items', itemSchema$1),
  8706. onSetup,
  8707. defaultedOnAction
  8708. ].concat(commonMenuItemFields));
  8709. const createCardMenuItem = spec => asRaw('cardmenuitem', cardMenuItemSchema, spec);
  8710. const choiceMenuItemSchema = objOf([
  8711. type,
  8712. active,
  8713. optionalIcon
  8714. ].concat(commonMenuItemFields));
  8715. const createChoiceMenuItem = spec => asRaw('choicemenuitem', choiceMenuItemSchema, spec);
  8716. const baseFields = [
  8717. type,
  8718. requiredString('fancytype'),
  8719. defaultedOnAction
  8720. ];
  8721. const insertTableFields = [defaulted('initData', {})].concat(baseFields);
  8722. const colorSwatchFields = [defaultedObjOf('initData', {}, [
  8723. defaultedBoolean('allowCustomColors', true),
  8724. optionArrayOf('colors', anyValue())
  8725. ])].concat(baseFields);
  8726. const fancyMenuItemSchema = choose$1('fancytype', {
  8727. inserttable: insertTableFields,
  8728. colorswatch: colorSwatchFields
  8729. });
  8730. const createFancyMenuItem = spec => asRaw('fancymenuitem', fancyMenuItemSchema, spec);
  8731. const menuItemSchema = objOf([
  8732. type,
  8733. onSetup,
  8734. defaultedOnAction,
  8735. optionalIcon
  8736. ].concat(commonMenuItemFields));
  8737. const createMenuItem = spec => asRaw('menuitem', menuItemSchema, spec);
  8738. const nestedMenuItemSchema = objOf([
  8739. type,
  8740. getSubmenuItems,
  8741. onSetup,
  8742. optionalIcon
  8743. ].concat(commonMenuItemFields));
  8744. const createNestedMenuItem = spec => asRaw('nestedmenuitem', nestedMenuItemSchema, spec);
  8745. const toggleMenuItemSchema = objOf([
  8746. type,
  8747. optionalIcon,
  8748. active,
  8749. onSetup,
  8750. onAction
  8751. ].concat(commonMenuItemFields));
  8752. const createToggleMenuItem = spec => asRaw('togglemenuitem', toggleMenuItemSchema, spec);
  8753. const detectSize = (comp, margin, selectorClass) => {
  8754. const descendants$1 = descendants(comp.element, '.' + selectorClass);
  8755. if (descendants$1.length > 0) {
  8756. const columnLength = findIndex$1(descendants$1, c => {
  8757. const thisTop = c.dom.getBoundingClientRect().top;
  8758. const cTop = descendants$1[0].dom.getBoundingClientRect().top;
  8759. return Math.abs(thisTop - cTop) > margin;
  8760. }).getOr(descendants$1.length);
  8761. return Optional.some({
  8762. numColumns: columnLength,
  8763. numRows: Math.ceil(descendants$1.length / columnLength)
  8764. });
  8765. } else {
  8766. return Optional.none();
  8767. }
  8768. };
  8769. const namedEvents = (name, handlers) => derive$1([config(name, handlers)]);
  8770. const unnamedEvents = handlers => namedEvents(generate$6('unnamed-events'), handlers);
  8771. const SimpleBehaviours = {
  8772. namedEvents,
  8773. unnamedEvents
  8774. };
  8775. const ExclusivityChannel = generate$6('tooltip.exclusive');
  8776. const ShowTooltipEvent = generate$6('tooltip.show');
  8777. const HideTooltipEvent = generate$6('tooltip.hide');
  8778. const hideAllExclusive = (component, _tConfig, _tState) => {
  8779. component.getSystem().broadcastOn([ExclusivityChannel], {});
  8780. };
  8781. const setComponents = (component, tConfig, tState, specs) => {
  8782. tState.getTooltip().each(tooltip => {
  8783. if (tooltip.getSystem().isConnected()) {
  8784. Replacing.set(tooltip, specs);
  8785. }
  8786. });
  8787. };
  8788. var TooltippingApis = /*#__PURE__*/Object.freeze({
  8789. __proto__: null,
  8790. hideAllExclusive: hideAllExclusive,
  8791. setComponents: setComponents
  8792. });
  8793. const events$9 = (tooltipConfig, state) => {
  8794. const hide = comp => {
  8795. state.getTooltip().each(p => {
  8796. detach(p);
  8797. tooltipConfig.onHide(comp, p);
  8798. state.clearTooltip();
  8799. });
  8800. state.clearTimer();
  8801. };
  8802. const show = comp => {
  8803. if (!state.isShowing()) {
  8804. hideAllExclusive(comp);
  8805. const sink = tooltipConfig.lazySink(comp).getOrDie();
  8806. const popup = comp.getSystem().build({
  8807. dom: tooltipConfig.tooltipDom,
  8808. components: tooltipConfig.tooltipComponents,
  8809. events: derive$2(tooltipConfig.mode === 'normal' ? [
  8810. run$1(mouseover(), _ => {
  8811. emit(comp, ShowTooltipEvent);
  8812. }),
  8813. run$1(mouseout(), _ => {
  8814. emit(comp, HideTooltipEvent);
  8815. })
  8816. ] : []),
  8817. behaviours: derive$1([Replacing.config({})])
  8818. });
  8819. state.setTooltip(popup);
  8820. attach(sink, popup);
  8821. tooltipConfig.onShow(comp, popup);
  8822. Positioning.position(sink, popup, { anchor: tooltipConfig.anchor(comp) });
  8823. }
  8824. };
  8825. return derive$2(flatten([
  8826. [
  8827. run$1(ShowTooltipEvent, comp => {
  8828. state.resetTimer(() => {
  8829. show(comp);
  8830. }, tooltipConfig.delay);
  8831. }),
  8832. run$1(HideTooltipEvent, comp => {
  8833. state.resetTimer(() => {
  8834. hide(comp);
  8835. }, tooltipConfig.delay);
  8836. }),
  8837. run$1(receive(), (comp, message) => {
  8838. const receivingData = message;
  8839. if (!receivingData.universal) {
  8840. if (contains$2(receivingData.channels, ExclusivityChannel)) {
  8841. hide(comp);
  8842. }
  8843. }
  8844. }),
  8845. runOnDetached(comp => {
  8846. hide(comp);
  8847. })
  8848. ],
  8849. tooltipConfig.mode === 'normal' ? [
  8850. run$1(focusin(), comp => {
  8851. emit(comp, ShowTooltipEvent);
  8852. }),
  8853. run$1(postBlur(), comp => {
  8854. emit(comp, HideTooltipEvent);
  8855. }),
  8856. run$1(mouseover(), comp => {
  8857. emit(comp, ShowTooltipEvent);
  8858. }),
  8859. run$1(mouseout(), comp => {
  8860. emit(comp, HideTooltipEvent);
  8861. })
  8862. ] : [
  8863. run$1(highlight$1(), (comp, _se) => {
  8864. emit(comp, ShowTooltipEvent);
  8865. }),
  8866. run$1(dehighlight$1(), comp => {
  8867. emit(comp, HideTooltipEvent);
  8868. })
  8869. ]
  8870. ]));
  8871. };
  8872. var ActiveTooltipping = /*#__PURE__*/Object.freeze({
  8873. __proto__: null,
  8874. events: events$9
  8875. });
  8876. var TooltippingSchema = [
  8877. required$1('lazySink'),
  8878. required$1('tooltipDom'),
  8879. defaulted('exclusive', true),
  8880. defaulted('tooltipComponents', []),
  8881. defaulted('delay', 300),
  8882. defaultedStringEnum('mode', 'normal', [
  8883. 'normal',
  8884. 'follow-highlight'
  8885. ]),
  8886. defaulted('anchor', comp => ({
  8887. type: 'hotspot',
  8888. hotspot: comp,
  8889. layouts: {
  8890. onLtr: constant$1([
  8891. south$2,
  8892. north$2,
  8893. southeast$2,
  8894. northeast$2,
  8895. southwest$2,
  8896. northwest$2
  8897. ]),
  8898. onRtl: constant$1([
  8899. south$2,
  8900. north$2,
  8901. southeast$2,
  8902. northeast$2,
  8903. southwest$2,
  8904. northwest$2
  8905. ])
  8906. }
  8907. })),
  8908. onHandler('onHide'),
  8909. onHandler('onShow')
  8910. ];
  8911. const init$b = () => {
  8912. const timer = value$2();
  8913. const popup = value$2();
  8914. const clearTimer = () => {
  8915. timer.on(clearTimeout);
  8916. };
  8917. const resetTimer = (f, delay) => {
  8918. clearTimer();
  8919. timer.set(setTimeout(f, delay));
  8920. };
  8921. const readState = constant$1('not-implemented');
  8922. return nu$8({
  8923. getTooltip: popup.get,
  8924. isShowing: popup.isSet,
  8925. setTooltip: popup.set,
  8926. clearTooltip: popup.clear,
  8927. clearTimer,
  8928. resetTimer,
  8929. readState
  8930. });
  8931. };
  8932. var TooltippingState = /*#__PURE__*/Object.freeze({
  8933. __proto__: null,
  8934. init: init$b
  8935. });
  8936. const Tooltipping = create$3({
  8937. fields: TooltippingSchema,
  8938. name: 'tooltipping',
  8939. active: ActiveTooltipping,
  8940. state: TooltippingState,
  8941. apis: TooltippingApis
  8942. });
  8943. const escape = text => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  8944. const ReadOnlyChannel = 'silver.readonly';
  8945. const ReadOnlyDataSchema = objOf([requiredBoolean('readonly')]);
  8946. const broadcastReadonly = (uiComponents, readonly) => {
  8947. const outerContainer = uiComponents.outerContainer;
  8948. const target = outerContainer.element;
  8949. if (readonly) {
  8950. uiComponents.mothership.broadcastOn([dismissPopups()], { target });
  8951. uiComponents.uiMothership.broadcastOn([dismissPopups()], { target });
  8952. }
  8953. uiComponents.mothership.broadcastOn([ReadOnlyChannel], { readonly });
  8954. uiComponents.uiMothership.broadcastOn([ReadOnlyChannel], { readonly });
  8955. };
  8956. const setupReadonlyModeSwitch = (editor, uiComponents) => {
  8957. editor.on('init', () => {
  8958. if (editor.mode.isReadOnly()) {
  8959. broadcastReadonly(uiComponents, true);
  8960. }
  8961. });
  8962. editor.on('SwitchMode', () => broadcastReadonly(uiComponents, editor.mode.isReadOnly()));
  8963. if (isReadOnly(editor)) {
  8964. editor.mode.set('readonly');
  8965. }
  8966. };
  8967. const receivingConfig = () => Receiving.config({
  8968. channels: {
  8969. [ReadOnlyChannel]: {
  8970. schema: ReadOnlyDataSchema,
  8971. onReceive: (comp, data) => {
  8972. Disabling.set(comp, data.readonly);
  8973. }
  8974. }
  8975. }
  8976. });
  8977. const item = disabled => Disabling.config({
  8978. disabled,
  8979. disableClass: 'tox-collection__item--state-disabled'
  8980. });
  8981. const button = disabled => Disabling.config({ disabled });
  8982. const splitButton = disabled => Disabling.config({
  8983. disabled,
  8984. disableClass: 'tox-tbtn--disabled'
  8985. });
  8986. const toolbarButton = disabled => Disabling.config({
  8987. disabled,
  8988. disableClass: 'tox-tbtn--disabled',
  8989. useNative: false
  8990. });
  8991. const DisablingConfigs = {
  8992. item,
  8993. button,
  8994. splitButton,
  8995. toolbarButton
  8996. };
  8997. const runWithApi = (info, comp) => {
  8998. const api = info.getApi(comp);
  8999. return f => {
  9000. f(api);
  9001. };
  9002. };
  9003. const onControlAttached = (info, editorOffCell) => runOnAttached(comp => {
  9004. const run = runWithApi(info, comp);
  9005. run(api => {
  9006. const onDestroy = info.onSetup(api);
  9007. if (isFunction(onDestroy)) {
  9008. editorOffCell.set(onDestroy);
  9009. }
  9010. });
  9011. });
  9012. const onControlDetached = (getApi, editorOffCell) => runOnDetached(comp => runWithApi(getApi, comp)(editorOffCell.get()));
  9013. const onMenuItemExecute = (info, itemResponse) => runOnExecute$1((comp, simulatedEvent) => {
  9014. runWithApi(info, comp)(info.onAction);
  9015. if (!info.triggersSubmenu && itemResponse === ItemResponse$1.CLOSE_ON_EXECUTE) {
  9016. if (comp.getSystem().isConnected()) {
  9017. emit(comp, sandboxClose());
  9018. }
  9019. simulatedEvent.stop();
  9020. }
  9021. });
  9022. const menuItemEventOrder = {
  9023. [execute$5()]: [
  9024. 'disabling',
  9025. 'alloy.base.behaviour',
  9026. 'toggling',
  9027. 'item-events'
  9028. ]
  9029. };
  9030. const componentRenderPipeline = cat;
  9031. const renderCommonItem = (spec, structure, itemResponse, providersbackstage) => {
  9032. const editorOffCell = Cell(noop);
  9033. return {
  9034. type: 'item',
  9035. dom: structure.dom,
  9036. components: componentRenderPipeline(structure.optComponents),
  9037. data: spec.data,
  9038. eventOrder: menuItemEventOrder,
  9039. hasSubmenu: spec.triggersSubmenu,
  9040. itemBehaviours: derive$1([
  9041. config('item-events', [
  9042. onMenuItemExecute(spec, itemResponse),
  9043. onControlAttached(spec, editorOffCell),
  9044. onControlDetached(spec, editorOffCell)
  9045. ]),
  9046. DisablingConfigs.item(() => !spec.enabled || providersbackstage.isDisabled()),
  9047. receivingConfig(),
  9048. Replacing.config({})
  9049. ].concat(spec.itemBehaviours))
  9050. };
  9051. };
  9052. const buildData = source => ({
  9053. value: source.value,
  9054. meta: {
  9055. text: source.text.getOr(''),
  9056. ...source.meta
  9057. }
  9058. });
  9059. const convertText = source => {
  9060. const isMac = global$5.os.isMacOS() || global$5.os.isiOS();
  9061. const mac = {
  9062. alt: '\u2325',
  9063. ctrl: '\u2303',
  9064. shift: '\u21E7',
  9065. meta: '\u2318',
  9066. access: '\u2303\u2325'
  9067. };
  9068. const other = {
  9069. meta: 'Ctrl',
  9070. access: 'Shift+Alt'
  9071. };
  9072. const replace = isMac ? mac : other;
  9073. const shortcut = source.split('+');
  9074. const updated = map$2(shortcut, segment => {
  9075. const search = segment.toLowerCase().trim();
  9076. return has$2(replace, search) ? replace[search] : segment;
  9077. });
  9078. return isMac ? updated.join('') : updated.join('+');
  9079. };
  9080. const renderIcon$1 = (name, icons, classes = [iconClass]) => render$3(name, {
  9081. tag: 'div',
  9082. classes
  9083. }, icons);
  9084. const renderText = text => ({
  9085. dom: {
  9086. tag: 'div',
  9087. classes: [textClass]
  9088. },
  9089. components: [text$1(global$8.translate(text))]
  9090. });
  9091. const renderHtml = (html, classes) => ({
  9092. dom: {
  9093. tag: 'div',
  9094. classes,
  9095. innerHtml: html
  9096. }
  9097. });
  9098. const renderStyledText = (style, text) => ({
  9099. dom: {
  9100. tag: 'div',
  9101. classes: [textClass]
  9102. },
  9103. components: [{
  9104. dom: {
  9105. tag: style.tag,
  9106. styles: style.styles
  9107. },
  9108. components: [text$1(global$8.translate(text))]
  9109. }]
  9110. });
  9111. const renderShortcut = shortcut => ({
  9112. dom: {
  9113. tag: 'div',
  9114. classes: [accessoryClass]
  9115. },
  9116. components: [text$1(convertText(shortcut))]
  9117. });
  9118. const renderCheckmark = icons => renderIcon$1('checkmark', icons, [checkmarkClass]);
  9119. const renderSubmenuCaret = icons => renderIcon$1('chevron-right', icons, [caretClass]);
  9120. const renderDownwardsCaret = icons => renderIcon$1('chevron-down', icons, [caretClass]);
  9121. const renderContainer = (container, components) => {
  9122. const directionClass = container.direction === 'vertical' ? containerColumnClass : containerRowClass;
  9123. const alignClass = container.align === 'left' ? containerAlignLeftClass : containerAlignRightClass;
  9124. const getValignClass = () => {
  9125. switch (container.valign) {
  9126. case 'top':
  9127. return containerValignTopClass;
  9128. case 'middle':
  9129. return containerValignMiddleClass;
  9130. case 'bottom':
  9131. return containerValignBottomClass;
  9132. }
  9133. };
  9134. return {
  9135. dom: {
  9136. tag: 'div',
  9137. classes: [
  9138. containerClass,
  9139. directionClass,
  9140. alignClass,
  9141. getValignClass()
  9142. ]
  9143. },
  9144. components
  9145. };
  9146. };
  9147. const renderImage = (src, classes, alt) => ({
  9148. dom: {
  9149. tag: 'img',
  9150. classes,
  9151. attributes: {
  9152. src,
  9153. alt: alt.getOr('')
  9154. }
  9155. }
  9156. });
  9157. const renderColorStructure = (item, providerBackstage, fallbackIcon) => {
  9158. const colorPickerCommand = 'custom';
  9159. const removeColorCommand = 'remove';
  9160. const itemText = item.ariaLabel;
  9161. const itemValue = item.value;
  9162. const iconSvg = item.iconContent.map(name => getOr(name, providerBackstage.icons, fallbackIcon));
  9163. const getDom = () => {
  9164. const common = colorClass;
  9165. const icon = iconSvg.getOr('');
  9166. const attributes = itemText.map(text => ({ title: providerBackstage.translate(text) })).getOr({});
  9167. const baseDom = {
  9168. tag: 'div',
  9169. attributes,
  9170. classes: [common]
  9171. };
  9172. if (itemValue === colorPickerCommand) {
  9173. return {
  9174. ...baseDom,
  9175. tag: 'button',
  9176. classes: [
  9177. ...baseDom.classes,
  9178. 'tox-swatches__picker-btn'
  9179. ],
  9180. innerHtml: icon
  9181. };
  9182. } else if (itemValue === removeColorCommand) {
  9183. return {
  9184. ...baseDom,
  9185. classes: [
  9186. ...baseDom.classes,
  9187. 'tox-swatch--remove'
  9188. ],
  9189. innerHtml: icon
  9190. };
  9191. } else {
  9192. return {
  9193. ...baseDom,
  9194. attributes: {
  9195. ...baseDom.attributes,
  9196. 'data-mce-color': itemValue
  9197. },
  9198. styles: { 'background-color': itemValue }
  9199. };
  9200. }
  9201. };
  9202. return {
  9203. dom: getDom(),
  9204. optComponents: []
  9205. };
  9206. };
  9207. const renderItemDomStructure = ariaLabel => {
  9208. const domTitle = ariaLabel.map(label => ({ attributes: { title: global$8.translate(label) } })).getOr({});
  9209. return {
  9210. tag: 'div',
  9211. classes: [
  9212. navClass,
  9213. selectableClass
  9214. ],
  9215. ...domTitle
  9216. };
  9217. };
  9218. const renderNormalItemStructure = (info, providersBackstage, renderIcons, fallbackIcon) => {
  9219. const iconSpec = {
  9220. tag: 'div',
  9221. classes: [iconClass]
  9222. };
  9223. const renderIcon = iconName => render$3(iconName, iconSpec, providersBackstage.icons, fallbackIcon);
  9224. const renderEmptyIcon = () => Optional.some({ dom: iconSpec });
  9225. const leftIcon = renderIcons ? info.iconContent.map(renderIcon).orThunk(renderEmptyIcon) : Optional.none();
  9226. const checkmark = info.checkMark;
  9227. const textRender = Optional.from(info.meta).fold(() => renderText, meta => has$2(meta, 'style') ? curry(renderStyledText, meta.style) : renderText);
  9228. const content = info.htmlContent.fold(() => info.textContent.map(textRender), html => Optional.some(renderHtml(html, [textClass])));
  9229. const menuItem = {
  9230. dom: renderItemDomStructure(info.ariaLabel),
  9231. optComponents: [
  9232. leftIcon,
  9233. content,
  9234. info.shortcutContent.map(renderShortcut),
  9235. checkmark,
  9236. info.caret
  9237. ]
  9238. };
  9239. return menuItem;
  9240. };
  9241. const renderItemStructure = (info, providersBackstage, renderIcons, fallbackIcon = Optional.none()) => {
  9242. if (info.presets === 'color') {
  9243. return renderColorStructure(info, providersBackstage, fallbackIcon);
  9244. } else {
  9245. return renderNormalItemStructure(info, providersBackstage, renderIcons, fallbackIcon);
  9246. }
  9247. };
  9248. const tooltipBehaviour = (meta, sharedBackstage) => get$g(meta, 'tooltipWorker').map(tooltipWorker => [Tooltipping.config({
  9249. lazySink: sharedBackstage.getSink,
  9250. tooltipDom: {
  9251. tag: 'div',
  9252. classes: ['tox-tooltip-worker-container']
  9253. },
  9254. tooltipComponents: [],
  9255. anchor: comp => ({
  9256. type: 'submenu',
  9257. item: comp,
  9258. overrides: { maxHeightFunction: expandable$1 }
  9259. }),
  9260. mode: 'follow-highlight',
  9261. onShow: (component, _tooltip) => {
  9262. tooltipWorker(elm => {
  9263. Tooltipping.setComponents(component, [external$1({ element: SugarElement.fromDom(elm) })]);
  9264. });
  9265. }
  9266. })]).getOr([]);
  9267. const encodeText = text => global$7.DOM.encode(text);
  9268. const replaceText = (text, matchText) => {
  9269. const translated = global$8.translate(text);
  9270. const encoded = encodeText(translated);
  9271. if (matchText.length > 0) {
  9272. const escapedMatchRegex = new RegExp(escape(matchText), 'gi');
  9273. return encoded.replace(escapedMatchRegex, match => `<span class="tox-autocompleter-highlight">${ match }</span>`);
  9274. } else {
  9275. return encoded;
  9276. }
  9277. };
  9278. const renderAutocompleteItem = (spec, matchText, useText, presets, onItemValueHandler, itemResponse, sharedBackstage, renderIcons = true) => {
  9279. const structure = renderItemStructure({
  9280. presets,
  9281. textContent: Optional.none(),
  9282. htmlContent: useText ? spec.text.map(text => replaceText(text, matchText)) : Optional.none(),
  9283. ariaLabel: spec.text,
  9284. iconContent: spec.icon,
  9285. shortcutContent: Optional.none(),
  9286. checkMark: Optional.none(),
  9287. caret: Optional.none(),
  9288. value: spec.value
  9289. }, sharedBackstage.providers, renderIcons, spec.icon);
  9290. return renderCommonItem({
  9291. data: buildData(spec),
  9292. enabled: spec.enabled,
  9293. getApi: constant$1({}),
  9294. onAction: _api => onItemValueHandler(spec.value, spec.meta),
  9295. onSetup: constant$1(noop),
  9296. triggersSubmenu: false,
  9297. itemBehaviours: tooltipBehaviour(spec.meta, sharedBackstage)
  9298. }, structure, itemResponse, sharedBackstage.providers);
  9299. };
  9300. const render$2 = (items, extras) => map$2(items, item => {
  9301. switch (item.type) {
  9302. case 'cardcontainer':
  9303. return renderContainer(item, render$2(item.items, extras));
  9304. case 'cardimage':
  9305. return renderImage(item.src, item.classes, item.alt);
  9306. case 'cardtext':
  9307. const shouldHighlight = item.name.exists(name => contains$2(extras.cardText.highlightOn, name));
  9308. const matchText = shouldHighlight ? Optional.from(extras.cardText.matchText).getOr('') : '';
  9309. return renderHtml(replaceText(item.text, matchText), item.classes);
  9310. }
  9311. });
  9312. const renderCardMenuItem = (spec, itemResponse, sharedBackstage, extras) => {
  9313. const getApi = component => ({
  9314. isEnabled: () => !Disabling.isDisabled(component),
  9315. setEnabled: state => {
  9316. Disabling.set(component, !state);
  9317. each$1(descendants(component.element, '*'), elm => {
  9318. component.getSystem().getByDom(elm).each(comp => {
  9319. if (comp.hasConfigured(Disabling)) {
  9320. Disabling.set(comp, !state);
  9321. }
  9322. });
  9323. });
  9324. }
  9325. });
  9326. const structure = {
  9327. dom: renderItemDomStructure(spec.label),
  9328. optComponents: [Optional.some({
  9329. dom: {
  9330. tag: 'div',
  9331. classes: [
  9332. containerClass,
  9333. containerRowClass
  9334. ]
  9335. },
  9336. components: render$2(spec.items, extras)
  9337. })]
  9338. };
  9339. return renderCommonItem({
  9340. data: buildData({
  9341. text: Optional.none(),
  9342. ...spec
  9343. }),
  9344. enabled: spec.enabled,
  9345. getApi,
  9346. onAction: spec.onAction,
  9347. onSetup: spec.onSetup,
  9348. triggersSubmenu: false,
  9349. itemBehaviours: Optional.from(extras.itemBehaviours).getOr([])
  9350. }, structure, itemResponse, sharedBackstage.providers);
  9351. };
  9352. const renderChoiceItem = (spec, useText, presets, onItemValueHandler, isSelected, itemResponse, providersBackstage, renderIcons = true) => {
  9353. const getApi = component => ({
  9354. setActive: state => {
  9355. Toggling.set(component, state);
  9356. },
  9357. isActive: () => Toggling.isOn(component),
  9358. isEnabled: () => !Disabling.isDisabled(component),
  9359. setEnabled: state => Disabling.set(component, !state)
  9360. });
  9361. const structure = renderItemStructure({
  9362. presets,
  9363. textContent: useText ? spec.text : Optional.none(),
  9364. htmlContent: Optional.none(),
  9365. ariaLabel: spec.text,
  9366. iconContent: spec.icon,
  9367. shortcutContent: useText ? spec.shortcut : Optional.none(),
  9368. checkMark: useText ? Optional.some(renderCheckmark(providersBackstage.icons)) : Optional.none(),
  9369. caret: Optional.none(),
  9370. value: spec.value
  9371. }, providersBackstage, renderIcons);
  9372. return deepMerge(renderCommonItem({
  9373. data: buildData(spec),
  9374. enabled: spec.enabled,
  9375. getApi,
  9376. onAction: _api => onItemValueHandler(spec.value),
  9377. onSetup: api => {
  9378. api.setActive(isSelected);
  9379. return noop;
  9380. },
  9381. triggersSubmenu: false,
  9382. itemBehaviours: []
  9383. }, structure, itemResponse, providersBackstage), {
  9384. toggling: {
  9385. toggleClass: tickedClass,
  9386. toggleOnExecute: false,
  9387. selected: spec.active,
  9388. exclusive: true
  9389. }
  9390. });
  9391. };
  9392. const parts$f = generate$3(owner$2(), parts$h());
  9393. const hexColour = value => ({ value });
  9394. const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  9395. const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  9396. const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
  9397. const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
  9398. const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
  9399. const getLongForm = hex => {
  9400. const hexString = hex.value.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b);
  9401. return { value: hexString };
  9402. };
  9403. const extractValues = hex => {
  9404. const longForm = getLongForm(hex);
  9405. const splitForm = longformRegex.exec(longForm.value);
  9406. return splitForm === null ? [
  9407. 'FFFFFF',
  9408. 'FF',
  9409. 'FF',
  9410. 'FF'
  9411. ] : splitForm;
  9412. };
  9413. const toHex = component => {
  9414. const hex = component.toString(16);
  9415. return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
  9416. };
  9417. const fromRgba = rgbaColour => {
  9418. const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
  9419. return hexColour(value);
  9420. };
  9421. const min = Math.min;
  9422. const max = Math.max;
  9423. const round$1 = Math.round;
  9424. const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  9425. const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  9426. const rgbaColour = (red, green, blue, alpha) => ({
  9427. red,
  9428. green,
  9429. blue,
  9430. alpha
  9431. });
  9432. const isRgbaComponent = value => {
  9433. const num = parseInt(value, 10);
  9434. return num.toString() === value && num >= 0 && num <= 255;
  9435. };
  9436. const fromHsv = hsv => {
  9437. let r;
  9438. let g;
  9439. let b;
  9440. const hue = (hsv.hue || 0) % 360;
  9441. let saturation = hsv.saturation / 100;
  9442. let brightness = hsv.value / 100;
  9443. saturation = max(0, min(saturation, 1));
  9444. brightness = max(0, min(brightness, 1));
  9445. if (saturation === 0) {
  9446. r = g = b = round$1(255 * brightness);
  9447. return rgbaColour(r, g, b, 1);
  9448. }
  9449. const side = hue / 60;
  9450. const chroma = brightness * saturation;
  9451. const x = chroma * (1 - Math.abs(side % 2 - 1));
  9452. const match = brightness - chroma;
  9453. switch (Math.floor(side)) {
  9454. case 0:
  9455. r = chroma;
  9456. g = x;
  9457. b = 0;
  9458. break;
  9459. case 1:
  9460. r = x;
  9461. g = chroma;
  9462. b = 0;
  9463. break;
  9464. case 2:
  9465. r = 0;
  9466. g = chroma;
  9467. b = x;
  9468. break;
  9469. case 3:
  9470. r = 0;
  9471. g = x;
  9472. b = chroma;
  9473. break;
  9474. case 4:
  9475. r = x;
  9476. g = 0;
  9477. b = chroma;
  9478. break;
  9479. case 5:
  9480. r = chroma;
  9481. g = 0;
  9482. b = x;
  9483. break;
  9484. default:
  9485. r = g = b = 0;
  9486. }
  9487. r = round$1(255 * (r + match));
  9488. g = round$1(255 * (g + match));
  9489. b = round$1(255 * (b + match));
  9490. return rgbaColour(r, g, b, 1);
  9491. };
  9492. const fromHex = hexColour => {
  9493. const result = extractValues(hexColour);
  9494. const red = parseInt(result[1], 16);
  9495. const green = parseInt(result[2], 16);
  9496. const blue = parseInt(result[3], 16);
  9497. return rgbaColour(red, green, blue, 1);
  9498. };
  9499. const fromStringValues = (red, green, blue, alpha) => {
  9500. const r = parseInt(red, 10);
  9501. const g = parseInt(green, 10);
  9502. const b = parseInt(blue, 10);
  9503. const a = parseFloat(alpha);
  9504. return rgbaColour(r, g, b, a);
  9505. };
  9506. const fromString = rgbaString => {
  9507. if (rgbaString === 'transparent') {
  9508. return Optional.some(rgbaColour(0, 0, 0, 0));
  9509. }
  9510. const rgbMatch = rgbRegex.exec(rgbaString);
  9511. if (rgbMatch !== null) {
  9512. return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
  9513. }
  9514. const rgbaMatch = rgbaRegex.exec(rgbaString);
  9515. if (rgbaMatch !== null) {
  9516. return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
  9517. }
  9518. return Optional.none();
  9519. };
  9520. const toString = rgba => `rgba(${ rgba.red },${ rgba.green },${ rgba.blue },${ rgba.alpha })`;
  9521. const red = rgbaColour(255, 0, 0, 1);
  9522. const fireSkinLoaded$1 = editor => editor.dispatch('SkinLoaded');
  9523. const fireSkinLoadError$1 = (editor, error) => editor.dispatch('SkinLoadError', error);
  9524. const fireResizeEditor = editor => editor.dispatch('ResizeEditor');
  9525. const fireResizeContent = (editor, e) => editor.dispatch('ResizeContent', e);
  9526. const fireScrollContent = (editor, e) => editor.dispatch('ScrollContent', e);
  9527. const fireTextColorChange = (editor, data) => editor.dispatch('TextColorChange', data);
  9528. const hsvColour = (hue, saturation, value) => ({
  9529. hue,
  9530. saturation,
  9531. value
  9532. });
  9533. const fromRgb = rgbaColour => {
  9534. let h = 0;
  9535. let s = 0;
  9536. let v = 0;
  9537. const r = rgbaColour.red / 255;
  9538. const g = rgbaColour.green / 255;
  9539. const b = rgbaColour.blue / 255;
  9540. const minRGB = Math.min(r, Math.min(g, b));
  9541. const maxRGB = Math.max(r, Math.max(g, b));
  9542. if (minRGB === maxRGB) {
  9543. v = minRGB;
  9544. return hsvColour(0, 0, v * 100);
  9545. }
  9546. const d = r === minRGB ? g - b : b === minRGB ? r - g : b - r;
  9547. h = r === minRGB ? 3 : b === minRGB ? 1 : 5;
  9548. h = 60 * (h - d / (maxRGB - minRGB));
  9549. s = (maxRGB - minRGB) / maxRGB;
  9550. v = maxRGB;
  9551. return hsvColour(Math.round(h), Math.round(s * 100), Math.round(v * 100));
  9552. };
  9553. const hexToHsv = hex => fromRgb(fromHex(hex));
  9554. const hsvToHex = hsv => fromRgba(fromHsv(hsv));
  9555. const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
  9556. const canvas = document.createElement('canvas');
  9557. canvas.height = 1;
  9558. canvas.width = 1;
  9559. const canvasContext = canvas.getContext('2d');
  9560. canvasContext.clearRect(0, 0, canvas.width, canvas.height);
  9561. canvasContext.fillStyle = '#FFFFFF';
  9562. canvasContext.fillStyle = color;
  9563. canvasContext.fillRect(0, 0, 1, 1);
  9564. const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
  9565. const r = rgba[0];
  9566. const g = rgba[1];
  9567. const b = rgba[2];
  9568. const a = rgba[3];
  9569. return fromRgba(rgbaColour(r, g, b, a));
  9570. });
  9571. var global$4 = tinymce.util.Tools.resolve('tinymce.util.LocalStorage');
  9572. const storageName = 'tinymce-custom-colors';
  9573. var ColorCache = (max = 10) => {
  9574. const storageString = global$4.getItem(storageName);
  9575. const localstorage = isString(storageString) ? JSON.parse(storageString) : [];
  9576. const prune = list => {
  9577. const diff = max - list.length;
  9578. return diff < 0 ? list.slice(0, max) : list;
  9579. };
  9580. const cache = prune(localstorage);
  9581. const add = key => {
  9582. indexOf(cache, key).each(remove);
  9583. cache.unshift(key);
  9584. if (cache.length > max) {
  9585. cache.pop();
  9586. }
  9587. global$4.setItem(storageName, JSON.stringify(cache));
  9588. };
  9589. const remove = idx => {
  9590. cache.splice(idx, 1);
  9591. };
  9592. const state = () => cache.slice(0);
  9593. return {
  9594. add,
  9595. state
  9596. };
  9597. };
  9598. const colorCache = ColorCache(10);
  9599. const calcCols = colors => Math.max(5, Math.ceil(Math.sqrt(colors)));
  9600. const mapColors = colorMap => {
  9601. const colors = [];
  9602. for (let i = 0; i < colorMap.length; i += 2) {
  9603. colors.push({
  9604. text: colorMap[i + 1],
  9605. value: '#' + anyToHex(colorMap[i]).value,
  9606. type: 'choiceitem'
  9607. });
  9608. }
  9609. return colors;
  9610. };
  9611. const option$1 = name => editor => editor.options.get(name);
  9612. const register$d = editor => {
  9613. const registerOption = editor.options.register;
  9614. registerOption('color_map', {
  9615. processor: value => {
  9616. if (isArrayOf(value, isString)) {
  9617. return {
  9618. value: mapColors(value),
  9619. valid: true
  9620. };
  9621. } else {
  9622. return {
  9623. valid: false,
  9624. message: 'Must be an array of strings.'
  9625. };
  9626. }
  9627. },
  9628. default: [
  9629. '#BFEDD2',
  9630. 'Light Green',
  9631. '#FBEEB8',
  9632. 'Light Yellow',
  9633. '#F8CAC6',
  9634. 'Light Red',
  9635. '#ECCAFA',
  9636. 'Light Purple',
  9637. '#C2E0F4',
  9638. 'Light Blue',
  9639. '#2DC26B',
  9640. 'Green',
  9641. '#F1C40F',
  9642. 'Yellow',
  9643. '#E03E2D',
  9644. 'Red',
  9645. '#B96AD9',
  9646. 'Purple',
  9647. '#3598DB',
  9648. 'Blue',
  9649. '#169179',
  9650. 'Dark Turquoise',
  9651. '#E67E23',
  9652. 'Orange',
  9653. '#BA372A',
  9654. 'Dark Red',
  9655. '#843FA1',
  9656. 'Dark Purple',
  9657. '#236FA1',
  9658. 'Dark Blue',
  9659. '#ECF0F1',
  9660. 'Light Gray',
  9661. '#CED4D9',
  9662. 'Medium Gray',
  9663. '#95A5A6',
  9664. 'Gray',
  9665. '#7E8C8D',
  9666. 'Dark Gray',
  9667. '#34495E',
  9668. 'Navy Blue',
  9669. '#000000',
  9670. 'Black',
  9671. '#ffffff',
  9672. 'White'
  9673. ]
  9674. });
  9675. registerOption('color_cols', {
  9676. processor: 'number',
  9677. default: calcCols(getColors$2(editor).length)
  9678. });
  9679. registerOption('custom_colors', {
  9680. processor: 'boolean',
  9681. default: true
  9682. });
  9683. };
  9684. const getColorCols$1 = option$1('color_cols');
  9685. const hasCustomColors$1 = option$1('custom_colors');
  9686. const getColors$2 = option$1('color_map');
  9687. const getCurrentColors = () => map$2(colorCache.state(), color => ({
  9688. type: 'choiceitem',
  9689. text: color,
  9690. value: color
  9691. }));
  9692. const addColor = color => {
  9693. colorCache.add(color);
  9694. };
  9695. const fallbackColor = '#000000';
  9696. const getCurrentColor = (editor, format) => {
  9697. let color;
  9698. editor.dom.getParents(editor.selection.getStart(), elm => {
  9699. let value;
  9700. if (value = elm.style[format === 'forecolor' ? 'color' : 'background-color']) {
  9701. color = color ? color : value;
  9702. }
  9703. });
  9704. return Optional.from(color);
  9705. };
  9706. const applyFormat = (editor, format, value) => {
  9707. editor.undoManager.transact(() => {
  9708. editor.focus();
  9709. editor.formatter.apply(format, { value });
  9710. editor.nodeChanged();
  9711. });
  9712. };
  9713. const removeFormat = (editor, format) => {
  9714. editor.undoManager.transact(() => {
  9715. editor.focus();
  9716. editor.formatter.remove(format, { value: null }, null, true);
  9717. editor.nodeChanged();
  9718. });
  9719. };
  9720. const registerCommands = editor => {
  9721. editor.addCommand('mceApplyTextcolor', (format, value) => {
  9722. applyFormat(editor, format, value);
  9723. });
  9724. editor.addCommand('mceRemoveTextcolor', format => {
  9725. removeFormat(editor, format);
  9726. });
  9727. };
  9728. const getAdditionalColors = hasCustom => {
  9729. const type = 'choiceitem';
  9730. const remove = {
  9731. type,
  9732. text: 'Remove color',
  9733. icon: 'color-swatch-remove-color',
  9734. value: 'remove'
  9735. };
  9736. const custom = {
  9737. type,
  9738. text: 'Custom color',
  9739. icon: 'color-picker',
  9740. value: 'custom'
  9741. };
  9742. return hasCustom ? [
  9743. remove,
  9744. custom
  9745. ] : [remove];
  9746. };
  9747. const applyColor = (editor, format, value, onChoice) => {
  9748. if (value === 'custom') {
  9749. const dialog = colorPickerDialog(editor);
  9750. dialog(colorOpt => {
  9751. colorOpt.each(color => {
  9752. addColor(color);
  9753. editor.execCommand('mceApplyTextcolor', format, color);
  9754. onChoice(color);
  9755. });
  9756. }, fallbackColor);
  9757. } else if (value === 'remove') {
  9758. onChoice('');
  9759. editor.execCommand('mceRemoveTextcolor', format);
  9760. } else {
  9761. onChoice(value);
  9762. editor.execCommand('mceApplyTextcolor', format, value);
  9763. }
  9764. };
  9765. const getColors$1 = (colors, hasCustom) => colors.concat(getCurrentColors().concat(getAdditionalColors(hasCustom)));
  9766. const getFetch$1 = (colors, hasCustom) => callback => {
  9767. callback(getColors$1(colors, hasCustom));
  9768. };
  9769. const setIconColor = (splitButtonApi, name, newColor) => {
  9770. const id = name === 'forecolor' ? 'tox-icon-text-color__color' : 'tox-icon-highlight-bg-color__color';
  9771. splitButtonApi.setIconFill(id, newColor);
  9772. };
  9773. const registerTextColorButton = (editor, name, format, tooltip, lastColor) => {
  9774. editor.ui.registry.addSplitButton(name, {
  9775. tooltip,
  9776. presets: 'color',
  9777. icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
  9778. select: value => {
  9779. const optCurrentRgb = getCurrentColor(editor, format);
  9780. return optCurrentRgb.bind(currentRgb => fromString(currentRgb).map(rgba => {
  9781. const currentHex = fromRgba(rgba).value;
  9782. return contains$1(value.toLowerCase(), currentHex);
  9783. })).getOr(false);
  9784. },
  9785. columns: getColorCols$1(editor),
  9786. fetch: getFetch$1(getColors$2(editor), hasCustomColors$1(editor)),
  9787. onAction: _splitButtonApi => {
  9788. applyColor(editor, format, lastColor.get(), noop);
  9789. },
  9790. onItemAction: (_splitButtonApi, value) => {
  9791. applyColor(editor, format, value, newColor => {
  9792. lastColor.set(newColor);
  9793. fireTextColorChange(editor, {
  9794. name,
  9795. color: newColor
  9796. });
  9797. });
  9798. },
  9799. onSetup: splitButtonApi => {
  9800. setIconColor(splitButtonApi, name, lastColor.get());
  9801. const handler = e => {
  9802. if (e.name === name) {
  9803. setIconColor(splitButtonApi, e.name, e.color);
  9804. }
  9805. };
  9806. editor.on('TextColorChange', handler);
  9807. return () => {
  9808. editor.off('TextColorChange', handler);
  9809. };
  9810. }
  9811. });
  9812. };
  9813. const registerTextColorMenuItem = (editor, name, format, text) => {
  9814. editor.ui.registry.addNestedMenuItem(name, {
  9815. text,
  9816. icon: name === 'forecolor' ? 'text-color' : 'highlight-bg-color',
  9817. getSubmenuItems: () => [{
  9818. type: 'fancymenuitem',
  9819. fancytype: 'colorswatch',
  9820. onAction: data => {
  9821. applyColor(editor, format, data.value, noop);
  9822. }
  9823. }]
  9824. });
  9825. };
  9826. const colorPickerDialog = editor => (callback, value) => {
  9827. let isValid = false;
  9828. const onSubmit = api => {
  9829. const data = api.getData();
  9830. const hex = data.colorpicker;
  9831. if (isValid) {
  9832. callback(Optional.from(hex));
  9833. api.close();
  9834. } else {
  9835. editor.windowManager.alert(editor.translate([
  9836. 'Invalid hex color code: {0}',
  9837. hex
  9838. ]));
  9839. }
  9840. };
  9841. const onAction = (_api, details) => {
  9842. if (details.name === 'hex-valid') {
  9843. isValid = details.value;
  9844. }
  9845. };
  9846. const initialData = { colorpicker: value };
  9847. editor.windowManager.open({
  9848. title: 'Color Picker',
  9849. size: 'normal',
  9850. body: {
  9851. type: 'panel',
  9852. items: [{
  9853. type: 'colorpicker',
  9854. name: 'colorpicker',
  9855. label: 'Color'
  9856. }]
  9857. },
  9858. buttons: [
  9859. {
  9860. type: 'cancel',
  9861. name: 'cancel',
  9862. text: 'Cancel'
  9863. },
  9864. {
  9865. type: 'submit',
  9866. name: 'save',
  9867. text: 'Save',
  9868. primary: true
  9869. }
  9870. ],
  9871. initialData,
  9872. onAction,
  9873. onSubmit,
  9874. onClose: noop,
  9875. onCancel: () => {
  9876. callback(Optional.none());
  9877. }
  9878. });
  9879. };
  9880. const register$c = editor => {
  9881. registerCommands(editor);
  9882. const lastForeColor = Cell(fallbackColor);
  9883. const lastBackColor = Cell(fallbackColor);
  9884. registerTextColorButton(editor, 'forecolor', 'forecolor', 'Text color', lastForeColor);
  9885. registerTextColorButton(editor, 'backcolor', 'hilitecolor', 'Background color', lastBackColor);
  9886. registerTextColorMenuItem(editor, 'forecolor', 'forecolor', 'Text color');
  9887. registerTextColorMenuItem(editor, 'backcolor', 'hilitecolor', 'Background color');
  9888. };
  9889. const createPartialChoiceMenu = (value, items, onItemValueHandler, columns, presets, itemResponse, select, providersBackstage) => {
  9890. const hasIcons = menuHasIcons(items);
  9891. const presetItemTypes = presets !== 'color' ? 'normal' : 'color';
  9892. const alloyItems = createChoiceItems(items, onItemValueHandler, columns, presetItemTypes, itemResponse, select, providersBackstage);
  9893. return createPartialMenuWithAlloyItems(value, hasIcons, alloyItems, columns, presets);
  9894. };
  9895. const createChoiceItems = (items, onItemValueHandler, columns, itemPresets, itemResponse, select, providersBackstage) => cat(map$2(items, item => {
  9896. if (item.type === 'choiceitem') {
  9897. return createChoiceMenuItem(item).fold(handleError, d => Optional.some(renderChoiceItem(d, columns === 1, itemPresets, onItemValueHandler, select(item.value), itemResponse, providersBackstage, menuHasIcons(items))));
  9898. } else {
  9899. return Optional.none();
  9900. }
  9901. }));
  9902. const deriveMenuMovement = (columns, presets) => {
  9903. const menuMarkers = markers(presets);
  9904. if (columns === 1) {
  9905. return {
  9906. mode: 'menu',
  9907. moveOnTab: true
  9908. };
  9909. } else if (columns === 'auto') {
  9910. return {
  9911. mode: 'grid',
  9912. selector: '.' + menuMarkers.item,
  9913. initSize: {
  9914. numColumns: 1,
  9915. numRows: 1
  9916. }
  9917. };
  9918. } else {
  9919. const rowClass = presets === 'color' ? 'tox-swatches__row' : 'tox-collection__group';
  9920. return {
  9921. mode: 'matrix',
  9922. rowSelector: '.' + rowClass
  9923. };
  9924. }
  9925. };
  9926. const deriveCollectionMovement = (columns, presets) => {
  9927. if (columns === 1) {
  9928. return {
  9929. mode: 'menu',
  9930. moveOnTab: false,
  9931. selector: '.tox-collection__item'
  9932. };
  9933. } else if (columns === 'auto') {
  9934. return {
  9935. mode: 'flatgrid',
  9936. selector: '.' + 'tox-collection__item',
  9937. initSize: {
  9938. numColumns: 1,
  9939. numRows: 1
  9940. }
  9941. };
  9942. } else {
  9943. return {
  9944. mode: 'matrix',
  9945. selectors: {
  9946. row: presets === 'color' ? '.tox-swatches__row' : '.tox-collection__group',
  9947. cell: presets === 'color' ? `.${ colorClass }` : `.${ selectableClass }`
  9948. }
  9949. };
  9950. }
  9951. };
  9952. const renderColorSwatchItem = (spec, backstage) => {
  9953. const items = getColorItems(spec, backstage);
  9954. const columns = backstage.colorinput.getColorCols();
  9955. const presets = 'color';
  9956. const menuSpec = createPartialChoiceMenu(generate$6('menu-value'), items, value => {
  9957. spec.onAction({ value });
  9958. }, columns, presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, backstage.shared.providers);
  9959. const widgetSpec = {
  9960. ...menuSpec,
  9961. markers: markers(presets),
  9962. movement: deriveMenuMovement(columns, presets)
  9963. };
  9964. return {
  9965. type: 'widget',
  9966. data: { value: generate$6('widget-id') },
  9967. dom: {
  9968. tag: 'div',
  9969. classes: ['tox-fancymenuitem']
  9970. },
  9971. autofocus: true,
  9972. components: [parts$f.widget(Menu.sketch(widgetSpec))]
  9973. };
  9974. };
  9975. const getColorItems = (spec, backstage) => {
  9976. const useCustomColors = spec.initData.allowCustomColors && backstage.colorinput.hasCustomColors();
  9977. return spec.initData.colors.fold(() => getColors$1(backstage.colorinput.getColors(), useCustomColors), colors => colors.concat(getAdditionalColors(useCustomColors)));
  9978. };
  9979. const cellOverEvent = generate$6('cell-over');
  9980. const cellExecuteEvent = generate$6('cell-execute');
  9981. const makeCell = (row, col, labelId) => {
  9982. const emitCellOver = c => emitWith(c, cellOverEvent, {
  9983. row,
  9984. col
  9985. });
  9986. const emitExecute = c => emitWith(c, cellExecuteEvent, {
  9987. row,
  9988. col
  9989. });
  9990. const onClick = (c, se) => {
  9991. se.stop();
  9992. emitExecute(c);
  9993. };
  9994. return build$1({
  9995. dom: {
  9996. tag: 'div',
  9997. attributes: {
  9998. role: 'button',
  9999. ['aria-labelledby']: labelId
  10000. }
  10001. },
  10002. behaviours: derive$1([
  10003. config('insert-table-picker-cell', [
  10004. run$1(mouseover(), Focusing.focus),
  10005. run$1(execute$5(), emitExecute),
  10006. run$1(click(), onClick),
  10007. run$1(tap(), onClick)
  10008. ]),
  10009. Toggling.config({
  10010. toggleClass: 'tox-insert-table-picker__selected',
  10011. toggleOnExecute: false
  10012. }),
  10013. Focusing.config({ onFocus: emitCellOver })
  10014. ])
  10015. });
  10016. };
  10017. const makeCells = (labelId, numRows, numCols) => {
  10018. const cells = [];
  10019. for (let i = 0; i < numRows; i++) {
  10020. const row = [];
  10021. for (let j = 0; j < numCols; j++) {
  10022. row.push(makeCell(i, j, labelId));
  10023. }
  10024. cells.push(row);
  10025. }
  10026. return cells;
  10027. };
  10028. const selectCells = (cells, selectedRow, selectedColumn, numRows, numColumns) => {
  10029. for (let i = 0; i < numRows; i++) {
  10030. for (let j = 0; j < numColumns; j++) {
  10031. Toggling.set(cells[i][j], i <= selectedRow && j <= selectedColumn);
  10032. }
  10033. }
  10034. };
  10035. const makeComponents = cells => bind$3(cells, cellRow => map$2(cellRow, premade));
  10036. const makeLabelText = (row, col) => text$1(`${ col }x${ row }`);
  10037. const renderInsertTableMenuItem = spec => {
  10038. const numRows = 10;
  10039. const numColumns = 10;
  10040. const sizeLabelId = generate$6('size-label');
  10041. const cells = makeCells(sizeLabelId, numRows, numColumns);
  10042. const emptyLabelText = makeLabelText(0, 0);
  10043. const memLabel = record({
  10044. dom: {
  10045. tag: 'span',
  10046. classes: ['tox-insert-table-picker__label'],
  10047. attributes: { id: sizeLabelId }
  10048. },
  10049. components: [emptyLabelText],
  10050. behaviours: derive$1([Replacing.config({})])
  10051. });
  10052. return {
  10053. type: 'widget',
  10054. data: { value: generate$6('widget-id') },
  10055. dom: {
  10056. tag: 'div',
  10057. classes: ['tox-fancymenuitem']
  10058. },
  10059. autofocus: true,
  10060. components: [parts$f.widget({
  10061. dom: {
  10062. tag: 'div',
  10063. classes: ['tox-insert-table-picker']
  10064. },
  10065. components: makeComponents(cells).concat(memLabel.asSpec()),
  10066. behaviours: derive$1([
  10067. config('insert-table-picker', [
  10068. runOnAttached(c => {
  10069. Replacing.set(memLabel.get(c), [emptyLabelText]);
  10070. }),
  10071. runWithTarget(cellOverEvent, (c, t, e) => {
  10072. const {row, col} = e.event;
  10073. selectCells(cells, row, col, numRows, numColumns);
  10074. Replacing.set(memLabel.get(c), [makeLabelText(row + 1, col + 1)]);
  10075. }),
  10076. runWithTarget(cellExecuteEvent, (c, _, e) => {
  10077. const {row, col} = e.event;
  10078. spec.onAction({
  10079. numRows: row + 1,
  10080. numColumns: col + 1
  10081. });
  10082. emit(c, sandboxClose());
  10083. })
  10084. ]),
  10085. Keying.config({
  10086. initSize: {
  10087. numRows,
  10088. numColumns
  10089. },
  10090. mode: 'flatgrid',
  10091. selector: '[role="button"]'
  10092. })
  10093. ])
  10094. })]
  10095. };
  10096. };
  10097. const fancyMenuItems = {
  10098. inserttable: renderInsertTableMenuItem,
  10099. colorswatch: renderColorSwatchItem
  10100. };
  10101. const renderFancyMenuItem = (spec, backstage) => get$g(fancyMenuItems, spec.fancytype).map(render => render(spec, backstage));
  10102. const renderNestedItem = (spec, itemResponse, providersBackstage, renderIcons = true, downwardsCaret = false) => {
  10103. const caret = downwardsCaret ? renderDownwardsCaret(providersBackstage.icons) : renderSubmenuCaret(providersBackstage.icons);
  10104. const getApi = component => ({
  10105. isEnabled: () => !Disabling.isDisabled(component),
  10106. setEnabled: state => Disabling.set(component, !state)
  10107. });
  10108. const structure = renderItemStructure({
  10109. presets: 'normal',
  10110. iconContent: spec.icon,
  10111. textContent: spec.text,
  10112. htmlContent: Optional.none(),
  10113. ariaLabel: spec.text,
  10114. caret: Optional.some(caret),
  10115. checkMark: Optional.none(),
  10116. shortcutContent: spec.shortcut
  10117. }, providersBackstage, renderIcons);
  10118. return renderCommonItem({
  10119. data: buildData(spec),
  10120. getApi,
  10121. enabled: spec.enabled,
  10122. onAction: noop,
  10123. onSetup: spec.onSetup,
  10124. triggersSubmenu: true,
  10125. itemBehaviours: []
  10126. }, structure, itemResponse, providersBackstage);
  10127. };
  10128. const renderNormalItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
  10129. const getApi = component => ({
  10130. isEnabled: () => !Disabling.isDisabled(component),
  10131. setEnabled: state => Disabling.set(component, !state)
  10132. });
  10133. const structure = renderItemStructure({
  10134. presets: 'normal',
  10135. iconContent: spec.icon,
  10136. textContent: spec.text,
  10137. htmlContent: Optional.none(),
  10138. ariaLabel: spec.text,
  10139. caret: Optional.none(),
  10140. checkMark: Optional.none(),
  10141. shortcutContent: spec.shortcut
  10142. }, providersBackstage, renderIcons);
  10143. return renderCommonItem({
  10144. data: buildData(spec),
  10145. getApi,
  10146. enabled: spec.enabled,
  10147. onAction: spec.onAction,
  10148. onSetup: spec.onSetup,
  10149. triggersSubmenu: false,
  10150. itemBehaviours: []
  10151. }, structure, itemResponse, providersBackstage);
  10152. };
  10153. const renderSeparatorItem = spec => ({
  10154. type: 'separator',
  10155. dom: {
  10156. tag: 'div',
  10157. classes: [
  10158. selectableClass,
  10159. groupHeadingClass
  10160. ]
  10161. },
  10162. components: spec.text.map(text$1).toArray()
  10163. });
  10164. const renderToggleMenuItem = (spec, itemResponse, providersBackstage, renderIcons = true) => {
  10165. const getApi = component => ({
  10166. setActive: state => {
  10167. Toggling.set(component, state);
  10168. },
  10169. isActive: () => Toggling.isOn(component),
  10170. isEnabled: () => !Disabling.isDisabled(component),
  10171. setEnabled: state => Disabling.set(component, !state)
  10172. });
  10173. const structure = renderItemStructure({
  10174. iconContent: spec.icon,
  10175. textContent: spec.text,
  10176. htmlContent: Optional.none(),
  10177. ariaLabel: spec.text,
  10178. checkMark: Optional.some(renderCheckmark(providersBackstage.icons)),
  10179. caret: Optional.none(),
  10180. shortcutContent: spec.shortcut,
  10181. presets: 'normal',
  10182. meta: spec.meta
  10183. }, providersBackstage, renderIcons);
  10184. return deepMerge(renderCommonItem({
  10185. data: buildData(spec),
  10186. enabled: spec.enabled,
  10187. getApi,
  10188. onAction: spec.onAction,
  10189. onSetup: spec.onSetup,
  10190. triggersSubmenu: false,
  10191. itemBehaviours: []
  10192. }, structure, itemResponse, providersBackstage), {
  10193. toggling: {
  10194. toggleClass: tickedClass,
  10195. toggleOnExecute: false,
  10196. selected: spec.active
  10197. }
  10198. });
  10199. };
  10200. const autocomplete = renderAutocompleteItem;
  10201. const separator$3 = renderSeparatorItem;
  10202. const normal = renderNormalItem;
  10203. const nested = renderNestedItem;
  10204. const toggle$1 = renderToggleMenuItem;
  10205. const fancy = renderFancyMenuItem;
  10206. const card = renderCardMenuItem;
  10207. var FocusMode;
  10208. (function (FocusMode) {
  10209. FocusMode[FocusMode['ContentFocus'] = 0] = 'ContentFocus';
  10210. FocusMode[FocusMode['UiFocus'] = 1] = 'UiFocus';
  10211. }(FocusMode || (FocusMode = {})));
  10212. const createMenuItemFromBridge = (item, itemResponse, backstage, menuHasIcons, isHorizontalMenu) => {
  10213. const providersBackstage = backstage.shared.providers;
  10214. const parseForHorizontalMenu = menuitem => !isHorizontalMenu ? menuitem : {
  10215. ...menuitem,
  10216. shortcut: Optional.none(),
  10217. icon: menuitem.text.isSome() ? Optional.none() : menuitem.icon
  10218. };
  10219. switch (item.type) {
  10220. case 'menuitem':
  10221. return createMenuItem(item).fold(handleError, d => Optional.some(normal(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
  10222. case 'nestedmenuitem':
  10223. return createNestedMenuItem(item).fold(handleError, d => Optional.some(nested(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons, isHorizontalMenu)));
  10224. case 'togglemenuitem':
  10225. return createToggleMenuItem(item).fold(handleError, d => Optional.some(toggle$1(parseForHorizontalMenu(d), itemResponse, providersBackstage, menuHasIcons)));
  10226. case 'separator':
  10227. return createSeparatorMenuItem(item).fold(handleError, d => Optional.some(separator$3(d)));
  10228. case 'fancymenuitem':
  10229. return createFancyMenuItem(item).fold(handleError, d => fancy(parseForHorizontalMenu(d), backstage));
  10230. default: {
  10231. console.error('Unknown item in general menu', item);
  10232. return Optional.none();
  10233. }
  10234. }
  10235. };
  10236. const createAutocompleteItems = (items, matchText, onItemValueHandler, columns, itemResponse, sharedBackstage, highlightOn) => {
  10237. const renderText = columns === 1;
  10238. const renderIcons = !renderText || menuHasIcons(items);
  10239. return cat(map$2(items, item => {
  10240. switch (item.type) {
  10241. case 'separator':
  10242. return createSeparatorItem(item).fold(handleError, d => Optional.some(separator$3(d)));
  10243. case 'cardmenuitem':
  10244. return createCardMenuItem(item).fold(handleError, d => Optional.some(card({
  10245. ...d,
  10246. onAction: api => {
  10247. d.onAction(api);
  10248. onItemValueHandler(d.value, d.meta);
  10249. }
  10250. }, itemResponse, sharedBackstage, {
  10251. itemBehaviours: tooltipBehaviour(d.meta, sharedBackstage),
  10252. cardText: {
  10253. matchText,
  10254. highlightOn
  10255. }
  10256. })));
  10257. case 'autocompleteitem':
  10258. default:
  10259. return createAutocompleterItem(item).fold(handleError, d => Optional.some(autocomplete(d, matchText, renderText, 'normal', onItemValueHandler, itemResponse, sharedBackstage, renderIcons)));
  10260. }
  10261. }));
  10262. };
  10263. const createPartialMenu = (value, items, itemResponse, backstage, isHorizontalMenu) => {
  10264. const hasIcons = menuHasIcons(items);
  10265. const alloyItems = cat(map$2(items, item => {
  10266. const itemHasIcon = i => isHorizontalMenu ? !has$2(i, 'text') : hasIcons;
  10267. const createItem = i => createMenuItemFromBridge(i, itemResponse, backstage, itemHasIcon(i), isHorizontalMenu);
  10268. if (item.type === 'nestedmenuitem' && item.getSubmenuItems().length <= 0) {
  10269. return createItem({
  10270. ...item,
  10271. enabled: false
  10272. });
  10273. } else {
  10274. return createItem(item);
  10275. }
  10276. }));
  10277. const createPartial = isHorizontalMenu ? createHorizontalPartialMenuWithAlloyItems : createPartialMenuWithAlloyItems;
  10278. return createPartial(value, hasIcons, alloyItems, 1, 'normal');
  10279. };
  10280. const createTieredDataFrom = partialMenu => tieredMenu.singleData(partialMenu.value, partialMenu);
  10281. const createInlineMenuFrom = (partialMenu, columns, focusMode, presets) => {
  10282. const movement = deriveMenuMovement(columns, presets);
  10283. const menuMarkers = markers(presets);
  10284. return {
  10285. data: createTieredDataFrom({
  10286. ...partialMenu,
  10287. movement,
  10288. menuBehaviours: SimpleBehaviours.unnamedEvents(columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
  10289. detectSize(comp, 4, menuMarkers.item).each(({numColumns, numRows}) => {
  10290. Keying.setGridSize(comp, numRows, numColumns);
  10291. });
  10292. })])
  10293. }),
  10294. menu: {
  10295. markers: markers(presets),
  10296. fakeFocus: focusMode === FocusMode.ContentFocus
  10297. }
  10298. };
  10299. };
  10300. const getAutocompleterRange = (dom, initRange) => {
  10301. return detect(SugarElement.fromDom(initRange.startContainer)).map(elm => {
  10302. const range = dom.createRng();
  10303. range.selectNode(elm.dom);
  10304. return range;
  10305. });
  10306. };
  10307. const register$b = (editor, sharedBackstage) => {
  10308. const processingAction = Cell(false);
  10309. const activeState = Cell(false);
  10310. const autocompleter = build$1(InlineView.sketch({
  10311. dom: {
  10312. tag: 'div',
  10313. classes: ['tox-autocompleter']
  10314. },
  10315. components: [],
  10316. fireDismissalEventInstead: {},
  10317. inlineBehaviours: derive$1([config('dismissAutocompleter', [run$1(dismissRequested(), () => cancelIfNecessary())])]),
  10318. lazySink: sharedBackstage.getSink
  10319. }));
  10320. const isMenuOpen = () => InlineView.isOpen(autocompleter);
  10321. const isActive = activeState.get;
  10322. const hideIfNecessary = () => {
  10323. if (isMenuOpen()) {
  10324. InlineView.hide(autocompleter);
  10325. }
  10326. };
  10327. const getMenu = () => InlineView.getContent(autocompleter).bind(tmenu => {
  10328. return get$h(tmenu.components(), 0);
  10329. });
  10330. const cancelIfNecessary = () => editor.execCommand('mceAutocompleterClose');
  10331. const getCombinedItems = matches => {
  10332. const columns = findMap(matches, m => Optional.from(m.columns)).getOr(1);
  10333. return bind$3(matches, match => {
  10334. const choices = match.items;
  10335. return createAutocompleteItems(choices, match.matchText, (itemValue, itemMeta) => {
  10336. const nr = editor.selection.getRng();
  10337. getAutocompleterRange(editor.dom, nr).each(range => {
  10338. const autocompleterApi = {
  10339. hide: () => cancelIfNecessary(),
  10340. reload: fetchOptions => {
  10341. hideIfNecessary();
  10342. editor.execCommand('mceAutocompleterReload', false, { fetchOptions });
  10343. }
  10344. };
  10345. processingAction.set(true);
  10346. match.onAction(autocompleterApi, range, itemValue, itemMeta);
  10347. processingAction.set(false);
  10348. });
  10349. }, columns, ItemResponse$1.BUBBLE_TO_SANDBOX, sharedBackstage, match.highlightOn);
  10350. });
  10351. };
  10352. const display = (lookupData, items) => {
  10353. findIn(SugarElement.fromDom(editor.getBody())).each(element => {
  10354. const columns = findMap(lookupData, ld => Optional.from(ld.columns)).getOr(1);
  10355. InlineView.showMenuAt(autocompleter, {
  10356. anchor: {
  10357. type: 'node',
  10358. root: SugarElement.fromDom(editor.getBody()),
  10359. node: Optional.from(element)
  10360. }
  10361. }, createInlineMenuFrom(createPartialMenuWithAlloyItems('autocompleter-value', true, items, columns, 'normal'), columns, FocusMode.ContentFocus, 'normal'));
  10362. });
  10363. getMenu().each(Highlighting.highlightFirst);
  10364. };
  10365. const updateDisplay = lookupData => {
  10366. const combinedItems = getCombinedItems(lookupData);
  10367. if (combinedItems.length > 0) {
  10368. display(lookupData, combinedItems);
  10369. } else {
  10370. hideIfNecessary();
  10371. }
  10372. };
  10373. editor.on('AutocompleterStart', ({lookupData}) => {
  10374. activeState.set(true);
  10375. processingAction.set(false);
  10376. updateDisplay(lookupData);
  10377. });
  10378. editor.on('AutocompleterUpdate', ({lookupData}) => updateDisplay(lookupData));
  10379. editor.on('AutocompleterEnd', () => {
  10380. hideIfNecessary();
  10381. activeState.set(false);
  10382. processingAction.set(false);
  10383. });
  10384. const autocompleterUiApi = {
  10385. cancelIfNecessary,
  10386. isMenuOpen,
  10387. isActive,
  10388. isProcessingAction: processingAction.get,
  10389. getMenu
  10390. };
  10391. AutocompleterEditorEvents.setup(autocompleterUiApi, editor);
  10392. };
  10393. const Autocompleter = { register: register$b };
  10394. const closest = (scope, selector, isRoot) => closest$1(scope, selector, isRoot).isSome();
  10395. const DelayedFunction = (fun, delay) => {
  10396. let ref = null;
  10397. const schedule = (...args) => {
  10398. ref = setTimeout(() => {
  10399. fun.apply(null, args);
  10400. ref = null;
  10401. }, delay);
  10402. };
  10403. const cancel = () => {
  10404. if (ref !== null) {
  10405. clearTimeout(ref);
  10406. ref = null;
  10407. }
  10408. };
  10409. return {
  10410. cancel,
  10411. schedule
  10412. };
  10413. };
  10414. const SIGNIFICANT_MOVE = 5;
  10415. const LONGPRESS_DELAY = 400;
  10416. const getTouch = event => {
  10417. const raw = event.raw;
  10418. if (raw.touches === undefined || raw.touches.length !== 1) {
  10419. return Optional.none();
  10420. }
  10421. return Optional.some(raw.touches[0]);
  10422. };
  10423. const isFarEnough = (touch, data) => {
  10424. const distX = Math.abs(touch.clientX - data.x);
  10425. const distY = Math.abs(touch.clientY - data.y);
  10426. return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
  10427. };
  10428. const monitor = settings => {
  10429. const startData = value$2();
  10430. const longpressFired = Cell(false);
  10431. const longpress$1 = DelayedFunction(event => {
  10432. settings.triggerEvent(longpress(), event);
  10433. longpressFired.set(true);
  10434. }, LONGPRESS_DELAY);
  10435. const handleTouchstart = event => {
  10436. getTouch(event).each(touch => {
  10437. longpress$1.cancel();
  10438. const data = {
  10439. x: touch.clientX,
  10440. y: touch.clientY,
  10441. target: event.target
  10442. };
  10443. longpress$1.schedule(event);
  10444. longpressFired.set(false);
  10445. startData.set(data);
  10446. });
  10447. return Optional.none();
  10448. };
  10449. const handleTouchmove = event => {
  10450. longpress$1.cancel();
  10451. getTouch(event).each(touch => {
  10452. startData.on(data => {
  10453. if (isFarEnough(touch, data)) {
  10454. startData.clear();
  10455. }
  10456. });
  10457. });
  10458. return Optional.none();
  10459. };
  10460. const handleTouchend = event => {
  10461. longpress$1.cancel();
  10462. const isSame = data => eq(data.target, event.target);
  10463. return startData.get().filter(isSame).map(_data => {
  10464. if (longpressFired.get()) {
  10465. event.prevent();
  10466. return false;
  10467. } else {
  10468. return settings.triggerEvent(tap(), event);
  10469. }
  10470. });
  10471. };
  10472. const handlers = wrapAll([
  10473. {
  10474. key: touchstart(),
  10475. value: handleTouchstart
  10476. },
  10477. {
  10478. key: touchmove(),
  10479. value: handleTouchmove
  10480. },
  10481. {
  10482. key: touchend(),
  10483. value: handleTouchend
  10484. }
  10485. ]);
  10486. const fireIfReady = (event, type) => get$g(handlers, type).bind(handler => handler(event));
  10487. return { fireIfReady };
  10488. };
  10489. const isDangerous = event => {
  10490. const keyEv = event.raw;
  10491. return keyEv.which === BACKSPACE[0] && !contains$2([
  10492. 'input',
  10493. 'textarea'
  10494. ], name$3(event.target)) && !closest(event.target, '[contenteditable="true"]');
  10495. };
  10496. const setup$d = (container, rawSettings) => {
  10497. const settings = {
  10498. stopBackspace: true,
  10499. ...rawSettings
  10500. };
  10501. const pointerEvents = [
  10502. 'touchstart',
  10503. 'touchmove',
  10504. 'touchend',
  10505. 'touchcancel',
  10506. 'gesturestart',
  10507. 'mousedown',
  10508. 'mouseup',
  10509. 'mouseover',
  10510. 'mousemove',
  10511. 'mouseout',
  10512. 'click'
  10513. ];
  10514. const tapEvent = monitor(settings);
  10515. const simpleEvents = map$2(pointerEvents.concat([
  10516. 'selectstart',
  10517. 'input',
  10518. 'contextmenu',
  10519. 'change',
  10520. 'transitionend',
  10521. 'transitioncancel',
  10522. 'drag',
  10523. 'dragstart',
  10524. 'dragend',
  10525. 'dragenter',
  10526. 'dragleave',
  10527. 'dragover',
  10528. 'drop',
  10529. 'keyup'
  10530. ]), type => bind(container, type, event => {
  10531. tapEvent.fireIfReady(event, type).each(tapStopped => {
  10532. if (tapStopped) {
  10533. event.kill();
  10534. }
  10535. });
  10536. const stopped = settings.triggerEvent(type, event);
  10537. if (stopped) {
  10538. event.kill();
  10539. }
  10540. }));
  10541. const pasteTimeout = value$2();
  10542. const onPaste = bind(container, 'paste', event => {
  10543. tapEvent.fireIfReady(event, 'paste').each(tapStopped => {
  10544. if (tapStopped) {
  10545. event.kill();
  10546. }
  10547. });
  10548. const stopped = settings.triggerEvent('paste', event);
  10549. if (stopped) {
  10550. event.kill();
  10551. }
  10552. pasteTimeout.set(setTimeout(() => {
  10553. settings.triggerEvent(postPaste(), event);
  10554. }, 0));
  10555. });
  10556. const onKeydown = bind(container, 'keydown', event => {
  10557. const stopped = settings.triggerEvent('keydown', event);
  10558. if (stopped) {
  10559. event.kill();
  10560. } else if (settings.stopBackspace && isDangerous(event)) {
  10561. event.prevent();
  10562. }
  10563. });
  10564. const onFocusIn = bind(container, 'focusin', event => {
  10565. const stopped = settings.triggerEvent('focusin', event);
  10566. if (stopped) {
  10567. event.kill();
  10568. }
  10569. });
  10570. const focusoutTimeout = value$2();
  10571. const onFocusOut = bind(container, 'focusout', event => {
  10572. const stopped = settings.triggerEvent('focusout', event);
  10573. if (stopped) {
  10574. event.kill();
  10575. }
  10576. focusoutTimeout.set(setTimeout(() => {
  10577. settings.triggerEvent(postBlur(), event);
  10578. }, 0));
  10579. });
  10580. const unbind = () => {
  10581. each$1(simpleEvents, e => {
  10582. e.unbind();
  10583. });
  10584. onKeydown.unbind();
  10585. onFocusIn.unbind();
  10586. onFocusOut.unbind();
  10587. onPaste.unbind();
  10588. pasteTimeout.on(clearTimeout);
  10589. focusoutTimeout.on(clearTimeout);
  10590. };
  10591. return { unbind };
  10592. };
  10593. const derive = (rawEvent, rawTarget) => {
  10594. const source = get$g(rawEvent, 'target').getOr(rawTarget);
  10595. return Cell(source);
  10596. };
  10597. const fromSource = (event, source) => {
  10598. const stopper = Cell(false);
  10599. const cutter = Cell(false);
  10600. const stop = () => {
  10601. stopper.set(true);
  10602. };
  10603. const cut = () => {
  10604. cutter.set(true);
  10605. };
  10606. return {
  10607. stop,
  10608. cut,
  10609. isStopped: stopper.get,
  10610. isCut: cutter.get,
  10611. event,
  10612. setSource: source.set,
  10613. getSource: source.get
  10614. };
  10615. };
  10616. const fromExternal = event => {
  10617. const stopper = Cell(false);
  10618. const stop = () => {
  10619. stopper.set(true);
  10620. };
  10621. return {
  10622. stop,
  10623. cut: noop,
  10624. isStopped: stopper.get,
  10625. isCut: never,
  10626. event,
  10627. setSource: die('Cannot set source of a broadcasted event'),
  10628. getSource: die('Cannot get source of a broadcasted event')
  10629. };
  10630. };
  10631. const adt$1 = Adt.generate([
  10632. { stopped: [] },
  10633. { resume: ['element'] },
  10634. { complete: [] }
  10635. ]);
  10636. const doTriggerHandler = (lookup, eventType, rawEvent, target, source, logger) => {
  10637. const handler = lookup(eventType, target);
  10638. const simulatedEvent = fromSource(rawEvent, source);
  10639. return handler.fold(() => {
  10640. logger.logEventNoHandlers(eventType, target);
  10641. return adt$1.complete();
  10642. }, handlerInfo => {
  10643. const descHandler = handlerInfo.descHandler;
  10644. const eventHandler = getCurried(descHandler);
  10645. eventHandler(simulatedEvent);
  10646. if (simulatedEvent.isStopped()) {
  10647. logger.logEventStopped(eventType, handlerInfo.element, descHandler.purpose);
  10648. return adt$1.stopped();
  10649. } else if (simulatedEvent.isCut()) {
  10650. logger.logEventCut(eventType, handlerInfo.element, descHandler.purpose);
  10651. return adt$1.complete();
  10652. } else {
  10653. return parent(handlerInfo.element).fold(() => {
  10654. logger.logNoParent(eventType, handlerInfo.element, descHandler.purpose);
  10655. return adt$1.complete();
  10656. }, parent => {
  10657. logger.logEventResponse(eventType, handlerInfo.element, descHandler.purpose);
  10658. return adt$1.resume(parent);
  10659. });
  10660. }
  10661. });
  10662. };
  10663. 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);
  10664. const triggerHandler = (lookup, eventType, rawEvent, target, logger) => {
  10665. const source = derive(rawEvent, target);
  10666. return doTriggerHandler(lookup, eventType, rawEvent, target, source, logger);
  10667. };
  10668. const broadcast = (listeners, rawEvent, _logger) => {
  10669. const simulatedEvent = fromExternal(rawEvent);
  10670. each$1(listeners, listener => {
  10671. const descHandler = listener.descHandler;
  10672. const handler = getCurried(descHandler);
  10673. handler(simulatedEvent);
  10674. });
  10675. return simulatedEvent.isStopped();
  10676. };
  10677. const triggerUntilStopped = (lookup, eventType, rawEvent, logger) => triggerOnUntilStopped(lookup, eventType, rawEvent, rawEvent.target, logger);
  10678. const triggerOnUntilStopped = (lookup, eventType, rawEvent, rawTarget, logger) => {
  10679. const source = derive(rawEvent, rawTarget);
  10680. return doTriggerOnUntilStopped(lookup, eventType, rawEvent, rawTarget, source, logger);
  10681. };
  10682. const eventHandler = (element, descHandler) => ({
  10683. element,
  10684. descHandler
  10685. });
  10686. const broadcastHandler = (id, handler) => ({
  10687. id,
  10688. descHandler: handler
  10689. });
  10690. const EventRegistry = () => {
  10691. const registry = {};
  10692. const registerId = (extraArgs, id, events) => {
  10693. each(events, (v, k) => {
  10694. const handlers = registry[k] !== undefined ? registry[k] : {};
  10695. handlers[id] = curryArgs(v, extraArgs);
  10696. registry[k] = handlers;
  10697. });
  10698. };
  10699. const findHandler = (handlers, elem) => read$1(elem).bind(id => get$g(handlers, id)).map(descHandler => eventHandler(elem, descHandler));
  10700. const filterByType = type => get$g(registry, type).map(handlers => mapToArray(handlers, (f, id) => broadcastHandler(id, f))).getOr([]);
  10701. const find = (isAboveRoot, type, target) => get$g(registry, type).bind(handlers => closest$4(target, elem => findHandler(handlers, elem), isAboveRoot));
  10702. const unregisterId = id => {
  10703. each(registry, (handlersById, _eventName) => {
  10704. if (has$2(handlersById, id)) {
  10705. delete handlersById[id];
  10706. }
  10707. });
  10708. };
  10709. return {
  10710. registerId,
  10711. unregisterId,
  10712. filterByType,
  10713. find
  10714. };
  10715. };
  10716. const Registry = () => {
  10717. const events = EventRegistry();
  10718. const components = {};
  10719. const readOrTag = component => {
  10720. const elem = component.element;
  10721. return read$1(elem).getOrThunk(() => write('uid-', component.element));
  10722. };
  10723. const failOnDuplicate = (component, tagId) => {
  10724. const conflict = components[tagId];
  10725. if (conflict === component) {
  10726. unregister(component);
  10727. } else {
  10728. 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');
  10729. }
  10730. };
  10731. const register = component => {
  10732. const tagId = readOrTag(component);
  10733. if (hasNonNullableKey(components, tagId)) {
  10734. failOnDuplicate(component, tagId);
  10735. }
  10736. const extraArgs = [component];
  10737. events.registerId(extraArgs, tagId, component.events);
  10738. components[tagId] = component;
  10739. };
  10740. const unregister = component => {
  10741. read$1(component.element).each(tagId => {
  10742. delete components[tagId];
  10743. events.unregisterId(tagId);
  10744. });
  10745. };
  10746. const filter = type => events.filterByType(type);
  10747. const find = (isAboveRoot, type, target) => events.find(isAboveRoot, type, target);
  10748. const getById = id => get$g(components, id);
  10749. return {
  10750. find,
  10751. filter,
  10752. register,
  10753. unregister,
  10754. getById
  10755. };
  10756. };
  10757. const factory$j = detail => {
  10758. const {attributes, ...domWithoutAttributes} = detail.dom;
  10759. return {
  10760. uid: detail.uid,
  10761. dom: {
  10762. tag: 'div',
  10763. attributes: {
  10764. role: 'presentation',
  10765. ...attributes
  10766. },
  10767. ...domWithoutAttributes
  10768. },
  10769. components: detail.components,
  10770. behaviours: get$3(detail.containerBehaviours),
  10771. events: detail.events,
  10772. domModification: detail.domModification,
  10773. eventOrder: detail.eventOrder
  10774. };
  10775. };
  10776. const Container = single({
  10777. name: 'Container',
  10778. factory: factory$j,
  10779. configFields: [
  10780. defaulted('components', []),
  10781. field('containerBehaviours', []),
  10782. defaulted('events', {}),
  10783. defaulted('domModification', {}),
  10784. defaulted('eventOrder', {})
  10785. ]
  10786. });
  10787. const takeover = root => {
  10788. const isAboveRoot = el => parent(root.element).fold(always, parent => eq(el, parent));
  10789. const registry = Registry();
  10790. const lookup = (eventName, target) => registry.find(isAboveRoot, eventName, target);
  10791. const domEvents = setup$d(root.element, {
  10792. triggerEvent: (eventName, event) => {
  10793. return monitorEvent(eventName, event.target, logger => triggerUntilStopped(lookup, eventName, event, logger));
  10794. }
  10795. });
  10796. const systemApi = {
  10797. debugInfo: constant$1('real'),
  10798. triggerEvent: (eventName, target, data) => {
  10799. monitorEvent(eventName, target, logger => triggerOnUntilStopped(lookup, eventName, data, target, logger));
  10800. },
  10801. triggerFocus: (target, originator) => {
  10802. read$1(target).fold(() => {
  10803. focus$3(target);
  10804. }, _alloyId => {
  10805. monitorEvent(focus$4(), target, logger => {
  10806. triggerHandler(lookup, focus$4(), {
  10807. originator,
  10808. kill: noop,
  10809. prevent: noop,
  10810. target
  10811. }, target, logger);
  10812. return false;
  10813. });
  10814. });
  10815. },
  10816. triggerEscape: (comp, simulatedEvent) => {
  10817. systemApi.triggerEvent('keydown', comp.element, simulatedEvent.event);
  10818. },
  10819. getByUid: uid => {
  10820. return getByUid(uid);
  10821. },
  10822. getByDom: elem => {
  10823. return getByDom(elem);
  10824. },
  10825. build: build$1,
  10826. buildOrPatch: buildOrPatch,
  10827. addToGui: c => {
  10828. add(c);
  10829. },
  10830. removeFromGui: c => {
  10831. remove(c);
  10832. },
  10833. addToWorld: c => {
  10834. addToWorld(c);
  10835. },
  10836. removeFromWorld: c => {
  10837. removeFromWorld(c);
  10838. },
  10839. broadcast: message => {
  10840. broadcast$1(message);
  10841. },
  10842. broadcastOn: (channels, message) => {
  10843. broadcastOn(channels, message);
  10844. },
  10845. broadcastEvent: (eventName, event) => {
  10846. broadcastEvent(eventName, event);
  10847. },
  10848. isConnected: always
  10849. };
  10850. const addToWorld = component => {
  10851. component.connect(systemApi);
  10852. if (!isText(component.element)) {
  10853. registry.register(component);
  10854. each$1(component.components(), addToWorld);
  10855. systemApi.triggerEvent(systemInit(), component.element, { target: component.element });
  10856. }
  10857. };
  10858. const removeFromWorld = component => {
  10859. if (!isText(component.element)) {
  10860. each$1(component.components(), removeFromWorld);
  10861. registry.unregister(component);
  10862. }
  10863. component.disconnect();
  10864. };
  10865. const add = component => {
  10866. attach(root, component);
  10867. };
  10868. const remove = component => {
  10869. detach(component);
  10870. };
  10871. const destroy = () => {
  10872. domEvents.unbind();
  10873. remove$5(root.element);
  10874. };
  10875. const broadcastData = data => {
  10876. const receivers = registry.filter(receive());
  10877. each$1(receivers, receiver => {
  10878. const descHandler = receiver.descHandler;
  10879. const handler = getCurried(descHandler);
  10880. handler(data);
  10881. });
  10882. };
  10883. const broadcast$1 = message => {
  10884. broadcastData({
  10885. universal: true,
  10886. data: message
  10887. });
  10888. };
  10889. const broadcastOn = (channels, message) => {
  10890. broadcastData({
  10891. universal: false,
  10892. channels,
  10893. data: message
  10894. });
  10895. };
  10896. const broadcastEvent = (eventName, event) => {
  10897. const listeners = registry.filter(eventName);
  10898. return broadcast(listeners, event);
  10899. };
  10900. const getByUid = uid => registry.getById(uid).fold(() => Result.error(new Error('Could not find component with uid: "' + uid + '" in system.')), Result.value);
  10901. const getByDom = elem => {
  10902. const uid = read$1(elem).getOr('not found');
  10903. return getByUid(uid);
  10904. };
  10905. addToWorld(root);
  10906. return {
  10907. root,
  10908. element: root.element,
  10909. destroy,
  10910. add,
  10911. remove,
  10912. getByUid,
  10913. getByDom,
  10914. addToWorld,
  10915. removeFromWorld,
  10916. broadcast: broadcast$1,
  10917. broadcastOn,
  10918. broadcastEvent
  10919. };
  10920. };
  10921. const renderBar = (spec, backstage) => ({
  10922. dom: {
  10923. tag: 'div',
  10924. classes: [
  10925. 'tox-bar',
  10926. 'tox-form__controls-h-stack'
  10927. ]
  10928. },
  10929. components: map$2(spec.items, backstage.interpreter)
  10930. });
  10931. const schema$l = constant$1([
  10932. defaulted('prefix', 'form-field'),
  10933. field('fieldBehaviours', [
  10934. Composing,
  10935. Representing
  10936. ])
  10937. ]);
  10938. const parts$e = constant$1([
  10939. optional({
  10940. schema: [required$1('dom')],
  10941. name: 'label'
  10942. }),
  10943. optional({
  10944. factory: {
  10945. sketch: spec => {
  10946. return {
  10947. uid: spec.uid,
  10948. dom: {
  10949. tag: 'span',
  10950. styles: { display: 'none' },
  10951. attributes: { 'aria-hidden': 'true' },
  10952. innerHtml: spec.text
  10953. }
  10954. };
  10955. }
  10956. },
  10957. schema: [required$1('text')],
  10958. name: 'aria-descriptor'
  10959. }),
  10960. required({
  10961. factory: {
  10962. sketch: spec => {
  10963. const excludeFactory = exclude(spec, ['factory']);
  10964. return spec.factory.sketch(excludeFactory);
  10965. }
  10966. },
  10967. schema: [required$1('factory')],
  10968. name: 'field'
  10969. })
  10970. ]);
  10971. const factory$i = (detail, components, _spec, _externals) => {
  10972. const behaviours = augment(detail.fieldBehaviours, [
  10973. Composing.config({
  10974. find: container => {
  10975. return getPart(container, detail, 'field');
  10976. }
  10977. }),
  10978. Representing.config({
  10979. store: {
  10980. mode: 'manual',
  10981. getValue: field => {
  10982. return Composing.getCurrent(field).bind(Representing.getValue);
  10983. },
  10984. setValue: (field, value) => {
  10985. Composing.getCurrent(field).each(current => {
  10986. Representing.setValue(current, value);
  10987. });
  10988. }
  10989. }
  10990. })
  10991. ]);
  10992. const events = derive$2([runOnAttached((component, _simulatedEvent) => {
  10993. const ps = getParts(component, detail, [
  10994. 'label',
  10995. 'field',
  10996. 'aria-descriptor'
  10997. ]);
  10998. ps.field().each(field => {
  10999. const id = generate$6(detail.prefix);
  11000. ps.label().each(label => {
  11001. set$9(label.element, 'for', id);
  11002. set$9(field.element, 'id', id);
  11003. });
  11004. ps['aria-descriptor']().each(descriptor => {
  11005. const descriptorId = generate$6(detail.prefix);
  11006. set$9(descriptor.element, 'id', descriptorId);
  11007. set$9(field.element, 'aria-describedby', descriptorId);
  11008. });
  11009. });
  11010. })]);
  11011. const apis = {
  11012. getField: container => getPart(container, detail, 'field'),
  11013. getLabel: container => getPart(container, detail, 'label')
  11014. };
  11015. return {
  11016. uid: detail.uid,
  11017. dom: detail.dom,
  11018. components,
  11019. behaviours,
  11020. events,
  11021. apis
  11022. };
  11023. };
  11024. const FormField = composite({
  11025. name: 'FormField',
  11026. configFields: schema$l(),
  11027. partFields: parts$e(),
  11028. factory: factory$i,
  11029. apis: {
  11030. getField: (apis, comp) => apis.getField(comp),
  11031. getLabel: (apis, comp) => apis.getLabel(comp)
  11032. }
  11033. });
  11034. const exhibit$2 = (base, tabConfig) => nu$7({
  11035. attributes: wrapAll([{
  11036. key: tabConfig.tabAttr,
  11037. value: 'true'
  11038. }])
  11039. });
  11040. var ActiveTabstopping = /*#__PURE__*/Object.freeze({
  11041. __proto__: null,
  11042. exhibit: exhibit$2
  11043. });
  11044. var TabstopSchema = [defaulted('tabAttr', 'data-alloy-tabstop')];
  11045. const Tabstopping = create$3({
  11046. fields: TabstopSchema,
  11047. name: 'tabstopping',
  11048. active: ActiveTabstopping
  11049. });
  11050. var global$3 = tinymce.util.Tools.resolve('tinymce.html.Entities');
  11051. const renderFormFieldWith = (pLabel, pField, extraClasses, extraBehaviours) => {
  11052. const spec = renderFormFieldSpecWith(pLabel, pField, extraClasses, extraBehaviours);
  11053. return FormField.sketch(spec);
  11054. };
  11055. const renderFormField = (pLabel, pField) => renderFormFieldWith(pLabel, pField, [], []);
  11056. const renderFormFieldSpecWith = (pLabel, pField, extraClasses, extraBehaviours) => ({
  11057. dom: renderFormFieldDomWith(extraClasses),
  11058. components: pLabel.toArray().concat([pField]),
  11059. fieldBehaviours: derive$1(extraBehaviours)
  11060. });
  11061. const renderFormFieldDom = () => renderFormFieldDomWith([]);
  11062. const renderFormFieldDomWith = extraClasses => ({
  11063. tag: 'div',
  11064. classes: ['tox-form__group'].concat(extraClasses)
  11065. });
  11066. const renderLabel$2 = (label, providersBackstage) => FormField.parts.label({
  11067. dom: {
  11068. tag: 'label',
  11069. classes: ['tox-label']
  11070. },
  11071. components: [text$1(providersBackstage.translate(label))]
  11072. });
  11073. const formChangeEvent = generate$6('form-component-change');
  11074. const formCloseEvent = generate$6('form-close');
  11075. const formCancelEvent = generate$6('form-cancel');
  11076. const formActionEvent = generate$6('form-action');
  11077. const formSubmitEvent = generate$6('form-submit');
  11078. const formBlockEvent = generate$6('form-block');
  11079. const formUnblockEvent = generate$6('form-unblock');
  11080. const formTabChangeEvent = generate$6('form-tabchange');
  11081. const formResizeEvent = generate$6('form-resize');
  11082. const renderCollection = (spec, providersBackstage, initialData) => {
  11083. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  11084. const runOnItem = f => (comp, se) => {
  11085. closest$1(se.event.target, '[data-collection-item-value]').each(target => {
  11086. f(comp, se, target, get$f(target, 'data-collection-item-value'));
  11087. });
  11088. };
  11089. const setContents = (comp, items) => {
  11090. const htmlLines = map$2(items, item => {
  11091. const itemText = global$8.translate(item.text);
  11092. const textContent = spec.columns === 1 ? `<div class="tox-collection__item-label">${ itemText }</div>` : '';
  11093. const iconContent = `<div class="tox-collection__item-icon">${ item.icon }</div>`;
  11094. const mapItemName = {
  11095. '_': ' ',
  11096. ' - ': ' ',
  11097. '-': ' '
  11098. };
  11099. const ariaLabel = itemText.replace(/\_| \- |\-/g, match => mapItemName[match]);
  11100. const disabledClass = providersBackstage.isDisabled() ? ' tox-collection__item--state-disabled' : '';
  11101. 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>`;
  11102. });
  11103. const chunks = spec.columns !== 'auto' && spec.columns > 1 ? chunk$1(htmlLines, spec.columns) : [htmlLines];
  11104. const html = map$2(chunks, ch => `<div class="tox-collection__group">${ ch.join('') }</div>`);
  11105. set$6(comp.element, html.join(''));
  11106. };
  11107. const onClick = runOnItem((comp, se, tgt, itemValue) => {
  11108. se.stop();
  11109. if (!providersBackstage.isDisabled()) {
  11110. emitWith(comp, formActionEvent, {
  11111. name: spec.name,
  11112. value: itemValue
  11113. });
  11114. }
  11115. });
  11116. const collectionEvents = [
  11117. run$1(mouseover(), runOnItem((comp, se, tgt) => {
  11118. focus$3(tgt);
  11119. })),
  11120. run$1(click(), onClick),
  11121. run$1(tap(), onClick),
  11122. run$1(focusin(), runOnItem((comp, se, tgt) => {
  11123. descendant(comp.element, '.' + activeClass).each(currentActive => {
  11124. remove$2(currentActive, activeClass);
  11125. });
  11126. add$2(tgt, activeClass);
  11127. })),
  11128. run$1(focusout(), runOnItem(comp => {
  11129. descendant(comp.element, '.' + activeClass).each(currentActive => {
  11130. remove$2(currentActive, activeClass);
  11131. });
  11132. })),
  11133. runOnExecute$1(runOnItem((comp, se, tgt, itemValue) => {
  11134. emitWith(comp, formActionEvent, {
  11135. name: spec.name,
  11136. value: itemValue
  11137. });
  11138. }))
  11139. ];
  11140. const iterCollectionItems = (comp, applyAttributes) => map$2(descendants(comp.element, '.tox-collection__item'), applyAttributes);
  11141. const pField = FormField.parts.field({
  11142. dom: {
  11143. tag: 'div',
  11144. classes: ['tox-collection'].concat(spec.columns !== 1 ? ['tox-collection--grid'] : ['tox-collection--list'])
  11145. },
  11146. components: [],
  11147. factory: { sketch: identity },
  11148. behaviours: derive$1([
  11149. Disabling.config({
  11150. disabled: providersBackstage.isDisabled,
  11151. onDisabled: comp => {
  11152. iterCollectionItems(comp, childElm => {
  11153. add$2(childElm, 'tox-collection__item--state-disabled');
  11154. set$9(childElm, 'aria-disabled', true);
  11155. });
  11156. },
  11157. onEnabled: comp => {
  11158. iterCollectionItems(comp, childElm => {
  11159. remove$2(childElm, 'tox-collection__item--state-disabled');
  11160. remove$7(childElm, 'aria-disabled');
  11161. });
  11162. }
  11163. }),
  11164. receivingConfig(),
  11165. Replacing.config({}),
  11166. Representing.config({
  11167. store: {
  11168. mode: 'memory',
  11169. initialValue: initialData.getOr([])
  11170. },
  11171. onSetValue: (comp, items) => {
  11172. setContents(comp, items);
  11173. if (spec.columns === 'auto') {
  11174. detectSize(comp, 5, 'tox-collection__item').each(({numRows, numColumns}) => {
  11175. Keying.setGridSize(comp, numRows, numColumns);
  11176. });
  11177. }
  11178. emit(comp, formResizeEvent);
  11179. }
  11180. }),
  11181. Tabstopping.config({}),
  11182. Keying.config(deriveCollectionMovement(spec.columns, 'normal')),
  11183. config('collection-events', collectionEvents)
  11184. ]),
  11185. eventOrder: {
  11186. [execute$5()]: [
  11187. 'disabling',
  11188. 'alloy.base.behaviour',
  11189. 'collection-events'
  11190. ]
  11191. }
  11192. });
  11193. const extraClasses = ['tox-form__group--collection'];
  11194. return renderFormFieldWith(pLabel, pField, extraClasses, []);
  11195. };
  11196. const schema$k = constant$1([
  11197. option$3('data'),
  11198. defaulted('inputAttributes', {}),
  11199. defaulted('inputStyles', {}),
  11200. defaulted('tag', 'input'),
  11201. defaulted('inputClasses', []),
  11202. onHandler('onSetValue'),
  11203. defaulted('styles', {}),
  11204. defaulted('eventOrder', {}),
  11205. field('inputBehaviours', [
  11206. Representing,
  11207. Focusing
  11208. ]),
  11209. defaulted('selectOnFocus', true)
  11210. ]);
  11211. const focusBehaviours = detail => derive$1([Focusing.config({
  11212. onFocus: !detail.selectOnFocus ? noop : component => {
  11213. const input = component.element;
  11214. const value = get$6(input);
  11215. input.dom.setSelectionRange(0, value.length);
  11216. }
  11217. })]);
  11218. const behaviours = detail => ({
  11219. ...focusBehaviours(detail),
  11220. ...augment(detail.inputBehaviours, [Representing.config({
  11221. store: {
  11222. mode: 'manual',
  11223. ...detail.data.map(data => ({ initialValue: data })).getOr({}),
  11224. getValue: input => {
  11225. return get$6(input.element);
  11226. },
  11227. setValue: (input, data) => {
  11228. const current = get$6(input.element);
  11229. if (current !== data) {
  11230. set$5(input.element, data);
  11231. }
  11232. }
  11233. },
  11234. onSetValue: detail.onSetValue
  11235. })])
  11236. });
  11237. const dom = detail => ({
  11238. tag: detail.tag,
  11239. attributes: {
  11240. type: 'text',
  11241. ...detail.inputAttributes
  11242. },
  11243. styles: detail.inputStyles,
  11244. classes: detail.inputClasses
  11245. });
  11246. const factory$h = (detail, _spec) => ({
  11247. uid: detail.uid,
  11248. dom: dom(detail),
  11249. components: [],
  11250. behaviours: behaviours(detail),
  11251. eventOrder: detail.eventOrder
  11252. });
  11253. const Input = single({
  11254. name: 'Input',
  11255. configFields: schema$k(),
  11256. factory: factory$h
  11257. });
  11258. const nu$3 = baseFn => {
  11259. let data = Optional.none();
  11260. let callbacks = [];
  11261. const map = f => nu$3(nCallback => {
  11262. get(data => {
  11263. nCallback(f(data));
  11264. });
  11265. });
  11266. const get = nCallback => {
  11267. if (isReady()) {
  11268. call(nCallback);
  11269. } else {
  11270. callbacks.push(nCallback);
  11271. }
  11272. };
  11273. const set = x => {
  11274. if (!isReady()) {
  11275. data = Optional.some(x);
  11276. run(callbacks);
  11277. callbacks = [];
  11278. }
  11279. };
  11280. const isReady = () => data.isSome();
  11281. const run = cbs => {
  11282. each$1(cbs, call);
  11283. };
  11284. const call = cb => {
  11285. data.each(x => {
  11286. setTimeout(() => {
  11287. cb(x);
  11288. }, 0);
  11289. });
  11290. };
  11291. baseFn(set);
  11292. return {
  11293. get,
  11294. map,
  11295. isReady
  11296. };
  11297. };
  11298. const pure$1 = a => nu$3(callback => {
  11299. callback(a);
  11300. });
  11301. const LazyValue = {
  11302. nu: nu$3,
  11303. pure: pure$1
  11304. };
  11305. const errorReporter = err => {
  11306. setTimeout(() => {
  11307. throw err;
  11308. }, 0);
  11309. };
  11310. const make$5 = run => {
  11311. const get = callback => {
  11312. run().then(callback, errorReporter);
  11313. };
  11314. const map = fab => {
  11315. return make$5(() => run().then(fab));
  11316. };
  11317. const bind = aFutureB => {
  11318. return make$5(() => run().then(v => aFutureB(v).toPromise()));
  11319. };
  11320. const anonBind = futureB => {
  11321. return make$5(() => run().then(() => futureB.toPromise()));
  11322. };
  11323. const toLazy = () => {
  11324. return LazyValue.nu(get);
  11325. };
  11326. const toCached = () => {
  11327. let cache = null;
  11328. return make$5(() => {
  11329. if (cache === null) {
  11330. cache = run();
  11331. }
  11332. return cache;
  11333. });
  11334. };
  11335. const toPromise = run;
  11336. return {
  11337. map,
  11338. bind,
  11339. anonBind,
  11340. toLazy,
  11341. toCached,
  11342. toPromise,
  11343. get
  11344. };
  11345. };
  11346. const nu$2 = baseFn => {
  11347. return make$5(() => new Promise(baseFn));
  11348. };
  11349. const pure = a => {
  11350. return make$5(() => Promise.resolve(a));
  11351. };
  11352. const Future = {
  11353. nu: nu$2,
  11354. pure
  11355. };
  11356. const ariaElements = [
  11357. 'input',
  11358. 'textarea'
  11359. ];
  11360. const isAriaElement = elem => {
  11361. const name = name$3(elem);
  11362. return contains$2(ariaElements, name);
  11363. };
  11364. const markValid = (component, invalidConfig) => {
  11365. const elem = invalidConfig.getRoot(component).getOr(component.element);
  11366. remove$2(elem, invalidConfig.invalidClass);
  11367. invalidConfig.notify.each(notifyInfo => {
  11368. if (isAriaElement(component.element)) {
  11369. set$9(component.element, 'aria-invalid', false);
  11370. }
  11371. notifyInfo.getContainer(component).each(container => {
  11372. set$6(container, notifyInfo.validHtml);
  11373. });
  11374. notifyInfo.onValid(component);
  11375. });
  11376. };
  11377. const markInvalid = (component, invalidConfig, invalidState, text) => {
  11378. const elem = invalidConfig.getRoot(component).getOr(component.element);
  11379. add$2(elem, invalidConfig.invalidClass);
  11380. invalidConfig.notify.each(notifyInfo => {
  11381. if (isAriaElement(component.element)) {
  11382. set$9(component.element, 'aria-invalid', true);
  11383. }
  11384. notifyInfo.getContainer(component).each(container => {
  11385. set$6(container, text);
  11386. });
  11387. notifyInfo.onInvalid(component, text);
  11388. });
  11389. };
  11390. const query = (component, invalidConfig, _invalidState) => invalidConfig.validator.fold(() => Future.pure(Result.value(true)), validatorInfo => validatorInfo.validate(component));
  11391. const run = (component, invalidConfig, invalidState) => {
  11392. invalidConfig.notify.each(notifyInfo => {
  11393. notifyInfo.onValidate(component);
  11394. });
  11395. return query(component, invalidConfig).map(valid => {
  11396. if (component.getSystem().isConnected()) {
  11397. return valid.fold(err => {
  11398. markInvalid(component, invalidConfig, invalidState, err);
  11399. return Result.error(err);
  11400. }, v => {
  11401. markValid(component, invalidConfig);
  11402. return Result.value(v);
  11403. });
  11404. } else {
  11405. return Result.error('No longer in system');
  11406. }
  11407. });
  11408. };
  11409. const isInvalid = (component, invalidConfig) => {
  11410. const elem = invalidConfig.getRoot(component).getOr(component.element);
  11411. return has(elem, invalidConfig.invalidClass);
  11412. };
  11413. var InvalidateApis = /*#__PURE__*/Object.freeze({
  11414. __proto__: null,
  11415. markValid: markValid,
  11416. markInvalid: markInvalid,
  11417. query: query,
  11418. run: run,
  11419. isInvalid: isInvalid
  11420. });
  11421. const events$8 = (invalidConfig, invalidState) => invalidConfig.validator.map(validatorInfo => derive$2([run$1(validatorInfo.onEvent, component => {
  11422. run(component, invalidConfig, invalidState).get(identity);
  11423. })].concat(validatorInfo.validateOnLoad ? [runOnAttached(component => {
  11424. run(component, invalidConfig, invalidState).get(noop);
  11425. })] : []))).getOr({});
  11426. var ActiveInvalidate = /*#__PURE__*/Object.freeze({
  11427. __proto__: null,
  11428. events: events$8
  11429. });
  11430. var InvalidateSchema = [
  11431. required$1('invalidClass'),
  11432. defaulted('getRoot', Optional.none),
  11433. optionObjOf('notify', [
  11434. defaulted('aria', 'alert'),
  11435. defaulted('getContainer', Optional.none),
  11436. defaulted('validHtml', ''),
  11437. onHandler('onValid'),
  11438. onHandler('onInvalid'),
  11439. onHandler('onValidate')
  11440. ]),
  11441. optionObjOf('validator', [
  11442. required$1('validate'),
  11443. defaulted('onEvent', 'input'),
  11444. defaulted('validateOnLoad', true)
  11445. ])
  11446. ];
  11447. const Invalidating = create$3({
  11448. fields: InvalidateSchema,
  11449. name: 'invalidating',
  11450. active: ActiveInvalidate,
  11451. apis: InvalidateApis,
  11452. extra: {
  11453. validation: validator => {
  11454. return component => {
  11455. const v = Representing.getValue(component);
  11456. return Future.pure(validator(v));
  11457. };
  11458. }
  11459. }
  11460. });
  11461. const getCoupled = (component, coupleConfig, coupleState, name) => coupleState.getOrCreate(component, coupleConfig, name);
  11462. var CouplingApis = /*#__PURE__*/Object.freeze({
  11463. __proto__: null,
  11464. getCoupled: getCoupled
  11465. });
  11466. var CouplingSchema = [requiredOf('others', setOf(Result.value, anyValue()))];
  11467. const init$a = () => {
  11468. const coupled = {};
  11469. const getOrCreate = (component, coupleConfig, name) => {
  11470. const available = keys(coupleConfig.others);
  11471. if (!available) {
  11472. throw new Error('Cannot find coupled component: ' + name + '. Known coupled components: ' + JSON.stringify(available, null, 2));
  11473. } else {
  11474. return get$g(coupled, name).getOrThunk(() => {
  11475. const builder = get$g(coupleConfig.others, name).getOrDie('No information found for coupled component: ' + name);
  11476. const spec = builder(component);
  11477. const built = component.getSystem().build(spec);
  11478. coupled[name] = built;
  11479. return built;
  11480. });
  11481. }
  11482. };
  11483. const readState = constant$1({});
  11484. return nu$8({
  11485. readState,
  11486. getOrCreate
  11487. });
  11488. };
  11489. var CouplingState = /*#__PURE__*/Object.freeze({
  11490. __proto__: null,
  11491. init: init$a
  11492. });
  11493. const Coupling = create$3({
  11494. fields: CouplingSchema,
  11495. name: 'coupling',
  11496. apis: CouplingApis,
  11497. state: CouplingState
  11498. });
  11499. const suffix = constant$1('sink');
  11500. const partType$1 = constant$1(optional({
  11501. name: suffix(),
  11502. overrides: constant$1({
  11503. dom: { tag: 'div' },
  11504. behaviours: derive$1([Positioning.config({ useFixed: always })]),
  11505. events: derive$2([
  11506. cutter(keydown()),
  11507. cutter(mousedown()),
  11508. cutter(click())
  11509. ])
  11510. })
  11511. }));
  11512. var HighlightOnOpen;
  11513. (function (HighlightOnOpen) {
  11514. HighlightOnOpen[HighlightOnOpen['HighlightFirst'] = 0] = 'HighlightFirst';
  11515. HighlightOnOpen[HighlightOnOpen['HighlightNone'] = 1] = 'HighlightNone';
  11516. }(HighlightOnOpen || (HighlightOnOpen = {})));
  11517. const getAnchor = (detail, component) => {
  11518. const hotspot = detail.getHotspot(component).getOr(component);
  11519. const type = 'hotspot';
  11520. const overrides = detail.getAnchorOverrides();
  11521. return detail.layouts.fold(() => ({
  11522. type,
  11523. hotspot,
  11524. overrides
  11525. }), layouts => ({
  11526. type,
  11527. hotspot,
  11528. overrides,
  11529. layouts
  11530. }));
  11531. };
  11532. const fetch = (detail, mapFetch, component) => {
  11533. const fetcher = detail.fetch;
  11534. return fetcher(component).map(mapFetch);
  11535. };
  11536. const openF = (detail, mapFetch, anchor, component, sandbox, externals, highlightOnOpen) => {
  11537. const futureData = fetch(detail, mapFetch, component);
  11538. const getLazySink = getSink(component, detail);
  11539. return futureData.map(tdata => tdata.bind(data => Optional.from(tieredMenu.sketch({
  11540. ...externals.menu(),
  11541. uid: generate$5(''),
  11542. data,
  11543. highlightImmediately: highlightOnOpen === HighlightOnOpen.HighlightFirst,
  11544. onOpenMenu: (tmenu, menu) => {
  11545. const sink = getLazySink().getOrDie();
  11546. Positioning.position(sink, menu, { anchor });
  11547. Sandboxing.decloak(sandbox);
  11548. },
  11549. onOpenSubmenu: (tmenu, item, submenu) => {
  11550. const sink = getLazySink().getOrDie();
  11551. Positioning.position(sink, submenu, {
  11552. anchor: {
  11553. type: 'submenu',
  11554. item
  11555. }
  11556. });
  11557. Sandboxing.decloak(sandbox);
  11558. },
  11559. onRepositionMenu: (tmenu, primaryMenu, submenuTriggers) => {
  11560. const sink = getLazySink().getOrDie();
  11561. Positioning.position(sink, primaryMenu, { anchor });
  11562. each$1(submenuTriggers, st => {
  11563. Positioning.position(sink, st.triggeredMenu, {
  11564. anchor: {
  11565. type: 'submenu',
  11566. item: st.triggeringItem
  11567. }
  11568. });
  11569. });
  11570. },
  11571. onEscape: () => {
  11572. Focusing.focus(component);
  11573. Sandboxing.close(sandbox);
  11574. return Optional.some(true);
  11575. }
  11576. }))));
  11577. };
  11578. const open = (detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen) => {
  11579. const anchor = getAnchor(detail, hotspot);
  11580. const processed = openF(detail, mapFetch, anchor, hotspot, sandbox, externals, highlightOnOpen);
  11581. return processed.map(tdata => {
  11582. tdata.fold(() => {
  11583. if (Sandboxing.isOpen(sandbox)) {
  11584. Sandboxing.close(sandbox);
  11585. }
  11586. }, data => {
  11587. Sandboxing.cloak(sandbox);
  11588. Sandboxing.open(sandbox, data);
  11589. onOpenSync(sandbox);
  11590. });
  11591. return sandbox;
  11592. });
  11593. };
  11594. const close = (detail, mapFetch, component, sandbox, _externals, _onOpenSync, _highlightOnOpen) => {
  11595. Sandboxing.close(sandbox);
  11596. return Future.pure(sandbox);
  11597. };
  11598. const togglePopup = (detail, mapFetch, hotspot, externals, onOpenSync, highlightOnOpen) => {
  11599. const sandbox = Coupling.getCoupled(hotspot, 'sandbox');
  11600. const showing = Sandboxing.isOpen(sandbox);
  11601. const action = showing ? close : open;
  11602. return action(detail, mapFetch, hotspot, sandbox, externals, onOpenSync, highlightOnOpen);
  11603. };
  11604. const matchWidth = (hotspot, container, useMinWidth) => {
  11605. const menu = Composing.getCurrent(container).getOr(container);
  11606. const buttonWidth = get$c(hotspot.element);
  11607. if (useMinWidth) {
  11608. set$8(menu.element, 'min-width', buttonWidth + 'px');
  11609. } else {
  11610. set$7(menu.element, buttonWidth);
  11611. }
  11612. };
  11613. 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)));
  11614. const doRepositionMenus = sandbox => {
  11615. Sandboxing.getState(sandbox).each(tmenu => {
  11616. tieredMenu.repositionMenus(tmenu);
  11617. });
  11618. };
  11619. const makeSandbox$1 = (detail, hotspot, extras) => {
  11620. const ariaControls = manager();
  11621. const onOpen = (component, menu) => {
  11622. const anchor = getAnchor(detail, hotspot);
  11623. ariaControls.link(hotspot.element);
  11624. if (detail.matchWidth) {
  11625. matchWidth(anchor.hotspot, menu, detail.useMinWidth);
  11626. }
  11627. detail.onOpen(anchor, component, menu);
  11628. if (extras !== undefined && extras.onOpen !== undefined) {
  11629. extras.onOpen(component, menu);
  11630. }
  11631. };
  11632. const onClose = (component, menu) => {
  11633. ariaControls.unlink(hotspot.element);
  11634. if (extras !== undefined && extras.onClose !== undefined) {
  11635. extras.onClose(component, menu);
  11636. }
  11637. };
  11638. const lazySink = getSink(hotspot, detail);
  11639. return {
  11640. dom: {
  11641. tag: 'div',
  11642. classes: detail.sandboxClasses,
  11643. attributes: {
  11644. id: ariaControls.id,
  11645. role: 'listbox'
  11646. }
  11647. },
  11648. behaviours: SketchBehaviours.augment(detail.sandboxBehaviours, [
  11649. Representing.config({
  11650. store: {
  11651. mode: 'memory',
  11652. initialValue: hotspot
  11653. }
  11654. }),
  11655. Sandboxing.config({
  11656. onOpen,
  11657. onClose,
  11658. isPartOf: (container, data, queryElem) => {
  11659. return isPartOf$1(data, queryElem) || isPartOf$1(hotspot, queryElem);
  11660. },
  11661. getAttachPoint: () => {
  11662. return lazySink().getOrDie();
  11663. }
  11664. }),
  11665. Composing.config({
  11666. find: sandbox => {
  11667. return Sandboxing.getState(sandbox).bind(menu => Composing.getCurrent(menu));
  11668. }
  11669. }),
  11670. Receiving.config({
  11671. channels: {
  11672. ...receivingChannel$1({ isExtraPart: never }),
  11673. ...receivingChannel({ doReposition: doRepositionMenus })
  11674. }
  11675. })
  11676. ])
  11677. };
  11678. };
  11679. const repositionMenus = comp => {
  11680. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  11681. doRepositionMenus(sandbox);
  11682. };
  11683. const sandboxFields = () => [
  11684. defaulted('sandboxClasses', []),
  11685. SketchBehaviours.field('sandboxBehaviours', [
  11686. Composing,
  11687. Receiving,
  11688. Sandboxing,
  11689. Representing
  11690. ])
  11691. ];
  11692. const schema$j = constant$1([
  11693. required$1('dom'),
  11694. required$1('fetch'),
  11695. onHandler('onOpen'),
  11696. onKeyboardHandler('onExecute'),
  11697. defaulted('getHotspot', Optional.some),
  11698. defaulted('getAnchorOverrides', constant$1({})),
  11699. schema$y(),
  11700. field('dropdownBehaviours', [
  11701. Toggling,
  11702. Coupling,
  11703. Keying,
  11704. Focusing
  11705. ]),
  11706. required$1('toggleClass'),
  11707. defaulted('eventOrder', {}),
  11708. option$3('lazySink'),
  11709. defaulted('matchWidth', false),
  11710. defaulted('useMinWidth', false),
  11711. option$3('role')
  11712. ].concat(sandboxFields()));
  11713. const parts$d = constant$1([
  11714. external({
  11715. schema: [tieredMenuMarkers()],
  11716. name: 'menu',
  11717. defaults: detail => {
  11718. return { onExecute: detail.onExecute };
  11719. }
  11720. }),
  11721. partType$1()
  11722. ]);
  11723. const factory$g = (detail, components, _spec, externals) => {
  11724. const lookupAttr = attr => get$g(detail.dom, 'attributes').bind(attrs => get$g(attrs, attr));
  11725. const switchToMenu = sandbox => {
  11726. Sandboxing.getState(sandbox).each(tmenu => {
  11727. tieredMenu.highlightPrimary(tmenu);
  11728. });
  11729. };
  11730. const action = component => {
  11731. const onOpenSync = switchToMenu;
  11732. togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
  11733. };
  11734. const apis = {
  11735. expand: comp => {
  11736. if (!Toggling.isOn(comp)) {
  11737. togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightNone).get(noop);
  11738. }
  11739. },
  11740. open: comp => {
  11741. if (!Toggling.isOn(comp)) {
  11742. togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightFirst).get(noop);
  11743. }
  11744. },
  11745. isOpen: Toggling.isOn,
  11746. close: comp => {
  11747. if (Toggling.isOn(comp)) {
  11748. togglePopup(detail, identity, comp, externals, noop, HighlightOnOpen.HighlightFirst).get(noop);
  11749. }
  11750. },
  11751. repositionMenus: comp => {
  11752. if (Toggling.isOn(comp)) {
  11753. repositionMenus(comp);
  11754. }
  11755. }
  11756. };
  11757. const triggerExecute = (comp, _se) => {
  11758. emitExecute(comp);
  11759. return Optional.some(true);
  11760. };
  11761. return {
  11762. uid: detail.uid,
  11763. dom: detail.dom,
  11764. components,
  11765. behaviours: augment(detail.dropdownBehaviours, [
  11766. Toggling.config({
  11767. toggleClass: detail.toggleClass,
  11768. aria: { mode: 'expanded' }
  11769. }),
  11770. Coupling.config({
  11771. others: {
  11772. sandbox: hotspot => {
  11773. return makeSandbox$1(detail, hotspot, {
  11774. onOpen: () => Toggling.on(hotspot),
  11775. onClose: () => Toggling.off(hotspot)
  11776. });
  11777. }
  11778. }
  11779. }),
  11780. Keying.config({
  11781. mode: 'special',
  11782. onSpace: triggerExecute,
  11783. onEnter: triggerExecute,
  11784. onDown: (comp, _se) => {
  11785. if (Dropdown.isOpen(comp)) {
  11786. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  11787. switchToMenu(sandbox);
  11788. } else {
  11789. Dropdown.open(comp);
  11790. }
  11791. return Optional.some(true);
  11792. },
  11793. onEscape: (comp, _se) => {
  11794. if (Dropdown.isOpen(comp)) {
  11795. Dropdown.close(comp);
  11796. return Optional.some(true);
  11797. } else {
  11798. return Optional.none();
  11799. }
  11800. }
  11801. }),
  11802. Focusing.config({})
  11803. ]),
  11804. events: events$a(Optional.some(action)),
  11805. eventOrder: {
  11806. ...detail.eventOrder,
  11807. [execute$5()]: [
  11808. 'disabling',
  11809. 'toggling',
  11810. 'alloy.base.behaviour'
  11811. ]
  11812. },
  11813. apis,
  11814. domModification: {
  11815. attributes: {
  11816. 'aria-haspopup': 'true',
  11817. ...detail.role.fold(() => ({}), role => ({ role })),
  11818. ...detail.dom.tag === 'button' ? { type: lookupAttr('type').getOr('button') } : {}
  11819. }
  11820. }
  11821. };
  11822. };
  11823. const Dropdown = composite({
  11824. name: 'Dropdown',
  11825. configFields: schema$j(),
  11826. partFields: parts$d(),
  11827. factory: factory$g,
  11828. apis: {
  11829. open: (apis, comp) => apis.open(comp),
  11830. expand: (apis, comp) => apis.expand(comp),
  11831. close: (apis, comp) => apis.close(comp),
  11832. isOpen: (apis, comp) => apis.isOpen(comp),
  11833. repositionMenus: (apis, comp) => apis.repositionMenus(comp)
  11834. }
  11835. });
  11836. const exhibit$1 = () => nu$7({
  11837. styles: {
  11838. '-webkit-user-select': 'none',
  11839. 'user-select': 'none',
  11840. '-ms-user-select': 'none',
  11841. '-moz-user-select': '-moz-none'
  11842. },
  11843. attributes: { unselectable: 'on' }
  11844. });
  11845. const events$7 = () => derive$2([abort(selectstart(), always)]);
  11846. var ActiveUnselecting = /*#__PURE__*/Object.freeze({
  11847. __proto__: null,
  11848. events: events$7,
  11849. exhibit: exhibit$1
  11850. });
  11851. const Unselecting = create$3({
  11852. fields: [],
  11853. name: 'unselecting',
  11854. active: ActiveUnselecting
  11855. });
  11856. const renderPanelButton = (spec, sharedBackstage) => Dropdown.sketch({
  11857. dom: spec.dom,
  11858. components: spec.components,
  11859. toggleClass: 'mce-active',
  11860. dropdownBehaviours: derive$1([
  11861. DisablingConfigs.button(sharedBackstage.providers.isDisabled),
  11862. receivingConfig(),
  11863. Unselecting.config({}),
  11864. Tabstopping.config({})
  11865. ]),
  11866. layouts: spec.layouts,
  11867. sandboxClasses: ['tox-dialog__popups'],
  11868. lazySink: sharedBackstage.getSink,
  11869. fetch: comp => Future.nu(callback => spec.fetch(callback)).map(items => Optional.from(createTieredDataFrom(deepMerge(createPartialChoiceMenu(generate$6('menu-value'), items, value => {
  11870. spec.onItemAction(comp, value);
  11871. }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, never, sharedBackstage.providers), { movement: deriveMenuMovement(spec.columns, spec.presets) })))),
  11872. parts: { menu: part(false, 1, spec.presets) }
  11873. });
  11874. const colorInputChangeEvent = generate$6('color-input-change');
  11875. const colorSwatchChangeEvent = generate$6('color-swatch-change');
  11876. const colorPickerCancelEvent = generate$6('color-picker-cancel');
  11877. const renderColorInput = (spec, sharedBackstage, colorInputBackstage, initialData) => {
  11878. const pField = FormField.parts.field({
  11879. factory: Input,
  11880. inputClasses: ['tox-textfield'],
  11881. data: initialData,
  11882. onSetValue: c => Invalidating.run(c).get(noop),
  11883. inputBehaviours: derive$1([
  11884. Disabling.config({ disabled: sharedBackstage.providers.isDisabled }),
  11885. receivingConfig(),
  11886. Tabstopping.config({}),
  11887. Invalidating.config({
  11888. invalidClass: 'tox-textbox-field-invalid',
  11889. getRoot: comp => parentElement(comp.element),
  11890. notify: {
  11891. onValid: comp => {
  11892. const val = Representing.getValue(comp);
  11893. emitWith(comp, colorInputChangeEvent, { color: val });
  11894. }
  11895. },
  11896. validator: {
  11897. validateOnLoad: false,
  11898. validate: input => {
  11899. const inputValue = Representing.getValue(input);
  11900. if (inputValue.length === 0) {
  11901. return Future.pure(Result.value(true));
  11902. } else {
  11903. const span = SugarElement.fromTag('span');
  11904. set$8(span, 'background-color', inputValue);
  11905. const res = getRaw(span, 'background-color').fold(() => Result.error('blah'), _ => Result.value(inputValue));
  11906. return Future.pure(res);
  11907. }
  11908. }
  11909. }
  11910. })
  11911. ]),
  11912. selectOnFocus: false
  11913. });
  11914. const pLabel = spec.label.map(label => renderLabel$2(label, sharedBackstage.providers));
  11915. const emitSwatchChange = (colorBit, value) => {
  11916. emitWith(colorBit, colorSwatchChangeEvent, { value });
  11917. };
  11918. const onItemAction = (comp, value) => {
  11919. memColorButton.getOpt(comp).each(colorBit => {
  11920. if (value === 'custom') {
  11921. colorInputBackstage.colorPicker(valueOpt => {
  11922. valueOpt.fold(() => emit(colorBit, colorPickerCancelEvent), value => {
  11923. emitSwatchChange(colorBit, value);
  11924. addColor(value);
  11925. });
  11926. }, '#ffffff');
  11927. } else if (value === 'remove') {
  11928. emitSwatchChange(colorBit, '');
  11929. } else {
  11930. emitSwatchChange(colorBit, value);
  11931. }
  11932. });
  11933. };
  11934. const memColorButton = record(renderPanelButton({
  11935. dom: {
  11936. tag: 'span',
  11937. attributes: { 'aria-label': sharedBackstage.providers.translate('Color swatch') }
  11938. },
  11939. layouts: {
  11940. onRtl: () => [
  11941. southwest$2,
  11942. southeast$2,
  11943. south$2
  11944. ],
  11945. onLtr: () => [
  11946. southeast$2,
  11947. southwest$2,
  11948. south$2
  11949. ]
  11950. },
  11951. components: [],
  11952. fetch: getFetch$1(colorInputBackstage.getColors(), colorInputBackstage.hasCustomColors()),
  11953. columns: colorInputBackstage.getColorCols(),
  11954. presets: 'color',
  11955. onItemAction
  11956. }, sharedBackstage));
  11957. return FormField.sketch({
  11958. dom: {
  11959. tag: 'div',
  11960. classes: ['tox-form__group']
  11961. },
  11962. components: pLabel.toArray().concat([{
  11963. dom: {
  11964. tag: 'div',
  11965. classes: ['tox-color-input']
  11966. },
  11967. components: [
  11968. pField,
  11969. memColorButton.asSpec()
  11970. ]
  11971. }]),
  11972. fieldBehaviours: derive$1([config('form-field-events', [
  11973. run$1(colorInputChangeEvent, (comp, se) => {
  11974. memColorButton.getOpt(comp).each(colorButton => {
  11975. set$8(colorButton.element, 'background-color', se.event.color);
  11976. });
  11977. emitWith(comp, formChangeEvent, { name: spec.name });
  11978. }),
  11979. run$1(colorSwatchChangeEvent, (comp, se) => {
  11980. FormField.getField(comp).each(field => {
  11981. Representing.setValue(field, se.event.value);
  11982. Composing.getCurrent(comp).each(Focusing.focus);
  11983. });
  11984. }),
  11985. run$1(colorPickerCancelEvent, (comp, _se) => {
  11986. FormField.getField(comp).each(_field => {
  11987. Composing.getCurrent(comp).each(Focusing.focus);
  11988. });
  11989. })
  11990. ])])
  11991. });
  11992. };
  11993. const labelPart = optional({
  11994. schema: [required$1('dom')],
  11995. name: 'label'
  11996. });
  11997. const edgePart = name => optional({
  11998. name: '' + name + '-edge',
  11999. overrides: detail => {
  12000. const action = detail.model.manager.edgeActions[name];
  12001. return action.fold(() => ({}), a => ({
  12002. events: derive$2([
  12003. runActionExtra(touchstart(), (comp, se, d) => a(comp, d), [detail]),
  12004. runActionExtra(mousedown(), (comp, se, d) => a(comp, d), [detail]),
  12005. runActionExtra(mousemove(), (comp, se, det) => {
  12006. if (det.mouseIsDown.get()) {
  12007. a(comp, det);
  12008. }
  12009. }, [detail])
  12010. ])
  12011. }));
  12012. }
  12013. });
  12014. const tlEdgePart = edgePart('top-left');
  12015. const tedgePart = edgePart('top');
  12016. const trEdgePart = edgePart('top-right');
  12017. const redgePart = edgePart('right');
  12018. const brEdgePart = edgePart('bottom-right');
  12019. const bedgePart = edgePart('bottom');
  12020. const blEdgePart = edgePart('bottom-left');
  12021. const ledgePart = edgePart('left');
  12022. const thumbPart = required({
  12023. name: 'thumb',
  12024. defaults: constant$1({ dom: { styles: { position: 'absolute' } } }),
  12025. overrides: detail => {
  12026. return {
  12027. events: derive$2([
  12028. redirectToPart(touchstart(), detail, 'spectrum'),
  12029. redirectToPart(touchmove(), detail, 'spectrum'),
  12030. redirectToPart(touchend(), detail, 'spectrum'),
  12031. redirectToPart(mousedown(), detail, 'spectrum'),
  12032. redirectToPart(mousemove(), detail, 'spectrum'),
  12033. redirectToPart(mouseup(), detail, 'spectrum')
  12034. ])
  12035. };
  12036. }
  12037. });
  12038. const spectrumPart = required({
  12039. schema: [customField('mouseIsDown', () => Cell(false))],
  12040. name: 'spectrum',
  12041. overrides: detail => {
  12042. const modelDetail = detail.model;
  12043. const model = modelDetail.manager;
  12044. const setValueFrom = (component, simulatedEvent) => model.getValueFromEvent(simulatedEvent).map(value => model.setValueFrom(component, detail, value));
  12045. return {
  12046. behaviours: derive$1([
  12047. Keying.config({
  12048. mode: 'special',
  12049. onLeft: spectrum => model.onLeft(spectrum, detail),
  12050. onRight: spectrum => model.onRight(spectrum, detail),
  12051. onUp: spectrum => model.onUp(spectrum, detail),
  12052. onDown: spectrum => model.onDown(spectrum, detail)
  12053. }),
  12054. Focusing.config({})
  12055. ]),
  12056. events: derive$2([
  12057. run$1(touchstart(), setValueFrom),
  12058. run$1(touchmove(), setValueFrom),
  12059. run$1(mousedown(), setValueFrom),
  12060. run$1(mousemove(), (spectrum, se) => {
  12061. if (detail.mouseIsDown.get()) {
  12062. setValueFrom(spectrum, se);
  12063. }
  12064. })
  12065. ])
  12066. };
  12067. }
  12068. });
  12069. var SliderParts = [
  12070. labelPart,
  12071. ledgePart,
  12072. redgePart,
  12073. tedgePart,
  12074. bedgePart,
  12075. tlEdgePart,
  12076. trEdgePart,
  12077. blEdgePart,
  12078. brEdgePart,
  12079. thumbPart,
  12080. spectrumPart
  12081. ];
  12082. const _sliderChangeEvent = 'slider.change.value';
  12083. const sliderChangeEvent = constant$1(_sliderChangeEvent);
  12084. const isTouchEvent$1 = evt => evt.type.indexOf('touch') !== -1;
  12085. const getEventSource = simulatedEvent => {
  12086. const evt = simulatedEvent.event.raw;
  12087. if (isTouchEvent$1(evt)) {
  12088. const touchEvent = evt;
  12089. return touchEvent.touches !== undefined && touchEvent.touches.length === 1 ? Optional.some(touchEvent.touches[0]).map(t => SugarPosition(t.clientX, t.clientY)) : Optional.none();
  12090. } else {
  12091. const mouseEvent = evt;
  12092. return mouseEvent.clientX !== undefined ? Optional.some(mouseEvent).map(me => SugarPosition(me.clientX, me.clientY)) : Optional.none();
  12093. }
  12094. };
  12095. const t = 'top', r = 'right', b = 'bottom', l = 'left';
  12096. const minX = detail => detail.model.minX;
  12097. const minY = detail => detail.model.minY;
  12098. const min1X = detail => detail.model.minX - 1;
  12099. const min1Y = detail => detail.model.minY - 1;
  12100. const maxX = detail => detail.model.maxX;
  12101. const maxY = detail => detail.model.maxY;
  12102. const max1X = detail => detail.model.maxX + 1;
  12103. const max1Y = detail => detail.model.maxY + 1;
  12104. const range = (detail, max, min) => max(detail) - min(detail);
  12105. const xRange = detail => range(detail, maxX, minX);
  12106. const yRange = detail => range(detail, maxY, minY);
  12107. const halfX = detail => xRange(detail) / 2;
  12108. const halfY = detail => yRange(detail) / 2;
  12109. const step = detail => detail.stepSize;
  12110. const snap = detail => detail.snapToGrid;
  12111. const snapStart = detail => detail.snapStart;
  12112. const rounded = detail => detail.rounded;
  12113. const hasEdge = (detail, edgeName) => detail[edgeName + '-edge'] !== undefined;
  12114. const hasLEdge = detail => hasEdge(detail, l);
  12115. const hasREdge = detail => hasEdge(detail, r);
  12116. const hasTEdge = detail => hasEdge(detail, t);
  12117. const hasBEdge = detail => hasEdge(detail, b);
  12118. const currentValue = detail => detail.model.value.get();
  12119. const xyValue = (x, y) => ({
  12120. x,
  12121. y
  12122. });
  12123. const fireSliderChange$3 = (component, value) => {
  12124. emitWith(component, sliderChangeEvent(), { value });
  12125. };
  12126. const setToTLEdgeXY = (edge, detail) => {
  12127. fireSliderChange$3(edge, xyValue(min1X(detail), min1Y(detail)));
  12128. };
  12129. const setToTEdge = (edge, detail) => {
  12130. fireSliderChange$3(edge, min1Y(detail));
  12131. };
  12132. const setToTEdgeXY = (edge, detail) => {
  12133. fireSliderChange$3(edge, xyValue(halfX(detail), min1Y(detail)));
  12134. };
  12135. const setToTREdgeXY = (edge, detail) => {
  12136. fireSliderChange$3(edge, xyValue(max1X(detail), min1Y(detail)));
  12137. };
  12138. const setToREdge = (edge, detail) => {
  12139. fireSliderChange$3(edge, max1X(detail));
  12140. };
  12141. const setToREdgeXY = (edge, detail) => {
  12142. fireSliderChange$3(edge, xyValue(max1X(detail), halfY(detail)));
  12143. };
  12144. const setToBREdgeXY = (edge, detail) => {
  12145. fireSliderChange$3(edge, xyValue(max1X(detail), max1Y(detail)));
  12146. };
  12147. const setToBEdge = (edge, detail) => {
  12148. fireSliderChange$3(edge, max1Y(detail));
  12149. };
  12150. const setToBEdgeXY = (edge, detail) => {
  12151. fireSliderChange$3(edge, xyValue(halfX(detail), max1Y(detail)));
  12152. };
  12153. const setToBLEdgeXY = (edge, detail) => {
  12154. fireSliderChange$3(edge, xyValue(min1X(detail), max1Y(detail)));
  12155. };
  12156. const setToLEdge = (edge, detail) => {
  12157. fireSliderChange$3(edge, min1X(detail));
  12158. };
  12159. const setToLEdgeXY = (edge, detail) => {
  12160. fireSliderChange$3(edge, xyValue(min1X(detail), halfY(detail)));
  12161. };
  12162. const reduceBy = (value, min, max, step) => {
  12163. if (value < min) {
  12164. return value;
  12165. } else if (value > max) {
  12166. return max;
  12167. } else if (value === min) {
  12168. return min - 1;
  12169. } else {
  12170. return Math.max(min, value - step);
  12171. }
  12172. };
  12173. const increaseBy = (value, min, max, step) => {
  12174. if (value > max) {
  12175. return value;
  12176. } else if (value < min) {
  12177. return min;
  12178. } else if (value === max) {
  12179. return max + 1;
  12180. } else {
  12181. return Math.min(max, value + step);
  12182. }
  12183. };
  12184. const capValue = (value, min, max) => Math.max(min, Math.min(max, value));
  12185. const snapValueOf = (value, min, max, step, snapStart) => snapStart.fold(() => {
  12186. const initValue = value - min;
  12187. const extraValue = Math.round(initValue / step) * step;
  12188. return capValue(min + extraValue, min - 1, max + 1);
  12189. }, start => {
  12190. const remainder = (value - start) % step;
  12191. const adjustment = Math.round(remainder / step);
  12192. const rawSteps = Math.floor((value - start) / step);
  12193. const maxSteps = Math.floor((max - start) / step);
  12194. const numSteps = Math.min(maxSteps, rawSteps + adjustment);
  12195. const r = start + numSteps * step;
  12196. return Math.max(start, r);
  12197. });
  12198. const findOffsetOf = (value, min, max) => Math.min(max, Math.max(value, min)) - min;
  12199. const findValueOf = args => {
  12200. const {min, max, range, value, step, snap, snapStart, rounded, hasMinEdge, hasMaxEdge, minBound, maxBound, screenRange} = args;
  12201. const capMin = hasMinEdge ? min - 1 : min;
  12202. const capMax = hasMaxEdge ? max + 1 : max;
  12203. if (value < minBound) {
  12204. return capMin;
  12205. } else if (value > maxBound) {
  12206. return capMax;
  12207. } else {
  12208. const offset = findOffsetOf(value, minBound, maxBound);
  12209. const newValue = capValue(offset / screenRange * range + min, capMin, capMax);
  12210. if (snap && newValue >= min && newValue <= max) {
  12211. return snapValueOf(newValue, min, max, step, snapStart);
  12212. } else if (rounded) {
  12213. return Math.round(newValue);
  12214. } else {
  12215. return newValue;
  12216. }
  12217. }
  12218. };
  12219. const findOffsetOfValue$2 = args => {
  12220. const {min, max, range, value, hasMinEdge, hasMaxEdge, maxBound, maxOffset, centerMinEdge, centerMaxEdge} = args;
  12221. if (value < min) {
  12222. return hasMinEdge ? 0 : centerMinEdge;
  12223. } else if (value > max) {
  12224. return hasMaxEdge ? maxBound : centerMaxEdge;
  12225. } else {
  12226. return (value - min) / range * maxOffset;
  12227. }
  12228. };
  12229. const top = 'top', right = 'right', bottom = 'bottom', left = 'left', width = 'width', height = 'height';
  12230. const getBounds = component => component.element.dom.getBoundingClientRect();
  12231. const getBoundsProperty = (bounds, property) => bounds[property];
  12232. const getMinXBounds = component => {
  12233. const bounds = getBounds(component);
  12234. return getBoundsProperty(bounds, left);
  12235. };
  12236. const getMaxXBounds = component => {
  12237. const bounds = getBounds(component);
  12238. return getBoundsProperty(bounds, right);
  12239. };
  12240. const getMinYBounds = component => {
  12241. const bounds = getBounds(component);
  12242. return getBoundsProperty(bounds, top);
  12243. };
  12244. const getMaxYBounds = component => {
  12245. const bounds = getBounds(component);
  12246. return getBoundsProperty(bounds, bottom);
  12247. };
  12248. const getXScreenRange = component => {
  12249. const bounds = getBounds(component);
  12250. return getBoundsProperty(bounds, width);
  12251. };
  12252. const getYScreenRange = component => {
  12253. const bounds = getBounds(component);
  12254. return getBoundsProperty(bounds, height);
  12255. };
  12256. const getCenterOffsetOf = (componentMinEdge, componentMaxEdge, spectrumMinEdge) => (componentMinEdge + componentMaxEdge) / 2 - spectrumMinEdge;
  12257. const getXCenterOffSetOf = (component, spectrum) => {
  12258. const componentBounds = getBounds(component);
  12259. const spectrumBounds = getBounds(spectrum);
  12260. const componentMinEdge = getBoundsProperty(componentBounds, left);
  12261. const componentMaxEdge = getBoundsProperty(componentBounds, right);
  12262. const spectrumMinEdge = getBoundsProperty(spectrumBounds, left);
  12263. return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  12264. };
  12265. const getYCenterOffSetOf = (component, spectrum) => {
  12266. const componentBounds = getBounds(component);
  12267. const spectrumBounds = getBounds(spectrum);
  12268. const componentMinEdge = getBoundsProperty(componentBounds, top);
  12269. const componentMaxEdge = getBoundsProperty(componentBounds, bottom);
  12270. const spectrumMinEdge = getBoundsProperty(spectrumBounds, top);
  12271. return getCenterOffsetOf(componentMinEdge, componentMaxEdge, spectrumMinEdge);
  12272. };
  12273. const fireSliderChange$2 = (spectrum, value) => {
  12274. emitWith(spectrum, sliderChangeEvent(), { value });
  12275. };
  12276. const findValueOfOffset$1 = (spectrum, detail, left) => {
  12277. const args = {
  12278. min: minX(detail),
  12279. max: maxX(detail),
  12280. range: xRange(detail),
  12281. value: left,
  12282. step: step(detail),
  12283. snap: snap(detail),
  12284. snapStart: snapStart(detail),
  12285. rounded: rounded(detail),
  12286. hasMinEdge: hasLEdge(detail),
  12287. hasMaxEdge: hasREdge(detail),
  12288. minBound: getMinXBounds(spectrum),
  12289. maxBound: getMaxXBounds(spectrum),
  12290. screenRange: getXScreenRange(spectrum)
  12291. };
  12292. return findValueOf(args);
  12293. };
  12294. const setValueFrom$2 = (spectrum, detail, value) => {
  12295. const xValue = findValueOfOffset$1(spectrum, detail, value);
  12296. const sliderVal = xValue;
  12297. fireSliderChange$2(spectrum, sliderVal);
  12298. return xValue;
  12299. };
  12300. const setToMin$2 = (spectrum, detail) => {
  12301. const min = minX(detail);
  12302. fireSliderChange$2(spectrum, min);
  12303. };
  12304. const setToMax$2 = (spectrum, detail) => {
  12305. const max = maxX(detail);
  12306. fireSliderChange$2(spectrum, max);
  12307. };
  12308. const moveBy$2 = (direction, spectrum, detail) => {
  12309. const f = direction > 0 ? increaseBy : reduceBy;
  12310. const xValue = f(currentValue(detail), minX(detail), maxX(detail), step(detail));
  12311. fireSliderChange$2(spectrum, xValue);
  12312. return Optional.some(xValue);
  12313. };
  12314. const handleMovement$2 = direction => (spectrum, detail) => moveBy$2(direction, spectrum, detail).map(always);
  12315. const getValueFromEvent$2 = simulatedEvent => {
  12316. const pos = getEventSource(simulatedEvent);
  12317. return pos.map(p => p.left);
  12318. };
  12319. const findOffsetOfValue$1 = (spectrum, detail, value, minEdge, maxEdge) => {
  12320. const minOffset = 0;
  12321. const maxOffset = getXScreenRange(spectrum);
  12322. const centerMinEdge = minEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(minOffset);
  12323. const centerMaxEdge = maxEdge.bind(edge => Optional.some(getXCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
  12324. const args = {
  12325. min: minX(detail),
  12326. max: maxX(detail),
  12327. range: xRange(detail),
  12328. value,
  12329. hasMinEdge: hasLEdge(detail),
  12330. hasMaxEdge: hasREdge(detail),
  12331. minBound: getMinXBounds(spectrum),
  12332. minOffset,
  12333. maxBound: getMaxXBounds(spectrum),
  12334. maxOffset,
  12335. centerMinEdge,
  12336. centerMaxEdge
  12337. };
  12338. return findOffsetOfValue$2(args);
  12339. };
  12340. const findPositionOfValue$1 = (slider, spectrum, value, minEdge, maxEdge, detail) => {
  12341. const offset = findOffsetOfValue$1(spectrum, detail, value, minEdge, maxEdge);
  12342. return getMinXBounds(spectrum) - getMinXBounds(slider) + offset;
  12343. };
  12344. const setPositionFromValue$2 = (slider, thumb, detail, edges) => {
  12345. const value = currentValue(detail);
  12346. const pos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
  12347. const thumbRadius = get$c(thumb.element) / 2;
  12348. set$8(thumb.element, 'left', pos - thumbRadius + 'px');
  12349. };
  12350. const onLeft$2 = handleMovement$2(-1);
  12351. const onRight$2 = handleMovement$2(1);
  12352. const onUp$2 = Optional.none;
  12353. const onDown$2 = Optional.none;
  12354. const edgeActions$2 = {
  12355. 'top-left': Optional.none(),
  12356. 'top': Optional.none(),
  12357. 'top-right': Optional.none(),
  12358. 'right': Optional.some(setToREdge),
  12359. 'bottom-right': Optional.none(),
  12360. 'bottom': Optional.none(),
  12361. 'bottom-left': Optional.none(),
  12362. 'left': Optional.some(setToLEdge)
  12363. };
  12364. var HorizontalModel = /*#__PURE__*/Object.freeze({
  12365. __proto__: null,
  12366. setValueFrom: setValueFrom$2,
  12367. setToMin: setToMin$2,
  12368. setToMax: setToMax$2,
  12369. findValueOfOffset: findValueOfOffset$1,
  12370. getValueFromEvent: getValueFromEvent$2,
  12371. findPositionOfValue: findPositionOfValue$1,
  12372. setPositionFromValue: setPositionFromValue$2,
  12373. onLeft: onLeft$2,
  12374. onRight: onRight$2,
  12375. onUp: onUp$2,
  12376. onDown: onDown$2,
  12377. edgeActions: edgeActions$2
  12378. });
  12379. const fireSliderChange$1 = (spectrum, value) => {
  12380. emitWith(spectrum, sliderChangeEvent(), { value });
  12381. };
  12382. const findValueOfOffset = (spectrum, detail, top) => {
  12383. const args = {
  12384. min: minY(detail),
  12385. max: maxY(detail),
  12386. range: yRange(detail),
  12387. value: top,
  12388. step: step(detail),
  12389. snap: snap(detail),
  12390. snapStart: snapStart(detail),
  12391. rounded: rounded(detail),
  12392. hasMinEdge: hasTEdge(detail),
  12393. hasMaxEdge: hasBEdge(detail),
  12394. minBound: getMinYBounds(spectrum),
  12395. maxBound: getMaxYBounds(spectrum),
  12396. screenRange: getYScreenRange(spectrum)
  12397. };
  12398. return findValueOf(args);
  12399. };
  12400. const setValueFrom$1 = (spectrum, detail, value) => {
  12401. const yValue = findValueOfOffset(spectrum, detail, value);
  12402. const sliderVal = yValue;
  12403. fireSliderChange$1(spectrum, sliderVal);
  12404. return yValue;
  12405. };
  12406. const setToMin$1 = (spectrum, detail) => {
  12407. const min = minY(detail);
  12408. fireSliderChange$1(spectrum, min);
  12409. };
  12410. const setToMax$1 = (spectrum, detail) => {
  12411. const max = maxY(detail);
  12412. fireSliderChange$1(spectrum, max);
  12413. };
  12414. const moveBy$1 = (direction, spectrum, detail) => {
  12415. const f = direction > 0 ? increaseBy : reduceBy;
  12416. const yValue = f(currentValue(detail), minY(detail), maxY(detail), step(detail));
  12417. fireSliderChange$1(spectrum, yValue);
  12418. return Optional.some(yValue);
  12419. };
  12420. const handleMovement$1 = direction => (spectrum, detail) => moveBy$1(direction, spectrum, detail).map(always);
  12421. const getValueFromEvent$1 = simulatedEvent => {
  12422. const pos = getEventSource(simulatedEvent);
  12423. return pos.map(p => {
  12424. return p.top;
  12425. });
  12426. };
  12427. const findOffsetOfValue = (spectrum, detail, value, minEdge, maxEdge) => {
  12428. const minOffset = 0;
  12429. const maxOffset = getYScreenRange(spectrum);
  12430. const centerMinEdge = minEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(minOffset);
  12431. const centerMaxEdge = maxEdge.bind(edge => Optional.some(getYCenterOffSetOf(edge, spectrum))).getOr(maxOffset);
  12432. const args = {
  12433. min: minY(detail),
  12434. max: maxY(detail),
  12435. range: yRange(detail),
  12436. value,
  12437. hasMinEdge: hasTEdge(detail),
  12438. hasMaxEdge: hasBEdge(detail),
  12439. minBound: getMinYBounds(spectrum),
  12440. minOffset,
  12441. maxBound: getMaxYBounds(spectrum),
  12442. maxOffset,
  12443. centerMinEdge,
  12444. centerMaxEdge
  12445. };
  12446. return findOffsetOfValue$2(args);
  12447. };
  12448. const findPositionOfValue = (slider, spectrum, value, minEdge, maxEdge, detail) => {
  12449. const offset = findOffsetOfValue(spectrum, detail, value, minEdge, maxEdge);
  12450. return getMinYBounds(spectrum) - getMinYBounds(slider) + offset;
  12451. };
  12452. const setPositionFromValue$1 = (slider, thumb, detail, edges) => {
  12453. const value = currentValue(detail);
  12454. const pos = findPositionOfValue(slider, edges.getSpectrum(slider), value, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
  12455. const thumbRadius = get$d(thumb.element) / 2;
  12456. set$8(thumb.element, 'top', pos - thumbRadius + 'px');
  12457. };
  12458. const onLeft$1 = Optional.none;
  12459. const onRight$1 = Optional.none;
  12460. const onUp$1 = handleMovement$1(-1);
  12461. const onDown$1 = handleMovement$1(1);
  12462. const edgeActions$1 = {
  12463. 'top-left': Optional.none(),
  12464. 'top': Optional.some(setToTEdge),
  12465. 'top-right': Optional.none(),
  12466. 'right': Optional.none(),
  12467. 'bottom-right': Optional.none(),
  12468. 'bottom': Optional.some(setToBEdge),
  12469. 'bottom-left': Optional.none(),
  12470. 'left': Optional.none()
  12471. };
  12472. var VerticalModel = /*#__PURE__*/Object.freeze({
  12473. __proto__: null,
  12474. setValueFrom: setValueFrom$1,
  12475. setToMin: setToMin$1,
  12476. setToMax: setToMax$1,
  12477. findValueOfOffset: findValueOfOffset,
  12478. getValueFromEvent: getValueFromEvent$1,
  12479. findPositionOfValue: findPositionOfValue,
  12480. setPositionFromValue: setPositionFromValue$1,
  12481. onLeft: onLeft$1,
  12482. onRight: onRight$1,
  12483. onUp: onUp$1,
  12484. onDown: onDown$1,
  12485. edgeActions: edgeActions$1
  12486. });
  12487. const fireSliderChange = (spectrum, value) => {
  12488. emitWith(spectrum, sliderChangeEvent(), { value });
  12489. };
  12490. const sliderValue = (x, y) => ({
  12491. x,
  12492. y
  12493. });
  12494. const setValueFrom = (spectrum, detail, value) => {
  12495. const xValue = findValueOfOffset$1(spectrum, detail, value.left);
  12496. const yValue = findValueOfOffset(spectrum, detail, value.top);
  12497. const val = sliderValue(xValue, yValue);
  12498. fireSliderChange(spectrum, val);
  12499. return val;
  12500. };
  12501. const moveBy = (direction, isVerticalMovement, spectrum, detail) => {
  12502. const f = direction > 0 ? increaseBy : reduceBy;
  12503. const xValue = isVerticalMovement ? currentValue(detail).x : f(currentValue(detail).x, minX(detail), maxX(detail), step(detail));
  12504. const yValue = !isVerticalMovement ? currentValue(detail).y : f(currentValue(detail).y, minY(detail), maxY(detail), step(detail));
  12505. fireSliderChange(spectrum, sliderValue(xValue, yValue));
  12506. return Optional.some(xValue);
  12507. };
  12508. const handleMovement = (direction, isVerticalMovement) => (spectrum, detail) => moveBy(direction, isVerticalMovement, spectrum, detail).map(always);
  12509. const setToMin = (spectrum, detail) => {
  12510. const mX = minX(detail);
  12511. const mY = minY(detail);
  12512. fireSliderChange(spectrum, sliderValue(mX, mY));
  12513. };
  12514. const setToMax = (spectrum, detail) => {
  12515. const mX = maxX(detail);
  12516. const mY = maxY(detail);
  12517. fireSliderChange(spectrum, sliderValue(mX, mY));
  12518. };
  12519. const getValueFromEvent = simulatedEvent => getEventSource(simulatedEvent);
  12520. const setPositionFromValue = (slider, thumb, detail, edges) => {
  12521. const value = currentValue(detail);
  12522. const xPos = findPositionOfValue$1(slider, edges.getSpectrum(slider), value.x, edges.getLeftEdge(slider), edges.getRightEdge(slider), detail);
  12523. const yPos = findPositionOfValue(slider, edges.getSpectrum(slider), value.y, edges.getTopEdge(slider), edges.getBottomEdge(slider), detail);
  12524. const thumbXRadius = get$c(thumb.element) / 2;
  12525. const thumbYRadius = get$d(thumb.element) / 2;
  12526. set$8(thumb.element, 'left', xPos - thumbXRadius + 'px');
  12527. set$8(thumb.element, 'top', yPos - thumbYRadius + 'px');
  12528. };
  12529. const onLeft = handleMovement(-1, false);
  12530. const onRight = handleMovement(1, false);
  12531. const onUp = handleMovement(-1, true);
  12532. const onDown = handleMovement(1, true);
  12533. const edgeActions = {
  12534. 'top-left': Optional.some(setToTLEdgeXY),
  12535. 'top': Optional.some(setToTEdgeXY),
  12536. 'top-right': Optional.some(setToTREdgeXY),
  12537. 'right': Optional.some(setToREdgeXY),
  12538. 'bottom-right': Optional.some(setToBREdgeXY),
  12539. 'bottom': Optional.some(setToBEdgeXY),
  12540. 'bottom-left': Optional.some(setToBLEdgeXY),
  12541. 'left': Optional.some(setToLEdgeXY)
  12542. };
  12543. var TwoDModel = /*#__PURE__*/Object.freeze({
  12544. __proto__: null,
  12545. setValueFrom: setValueFrom,
  12546. setToMin: setToMin,
  12547. setToMax: setToMax,
  12548. getValueFromEvent: getValueFromEvent,
  12549. setPositionFromValue: setPositionFromValue,
  12550. onLeft: onLeft,
  12551. onRight: onRight,
  12552. onUp: onUp,
  12553. onDown: onDown,
  12554. edgeActions: edgeActions
  12555. });
  12556. const SliderSchema = [
  12557. defaulted('stepSize', 1),
  12558. defaulted('onChange', noop),
  12559. defaulted('onChoose', noop),
  12560. defaulted('onInit', noop),
  12561. defaulted('onDragStart', noop),
  12562. defaulted('onDragEnd', noop),
  12563. defaulted('snapToGrid', false),
  12564. defaulted('rounded', true),
  12565. option$3('snapStart'),
  12566. requiredOf('model', choose$1('mode', {
  12567. x: [
  12568. defaulted('minX', 0),
  12569. defaulted('maxX', 100),
  12570. customField('value', spec => Cell(spec.mode.minX)),
  12571. required$1('getInitialValue'),
  12572. output$1('manager', HorizontalModel)
  12573. ],
  12574. y: [
  12575. defaulted('minY', 0),
  12576. defaulted('maxY', 100),
  12577. customField('value', spec => Cell(spec.mode.minY)),
  12578. required$1('getInitialValue'),
  12579. output$1('manager', VerticalModel)
  12580. ],
  12581. xy: [
  12582. defaulted('minX', 0),
  12583. defaulted('maxX', 100),
  12584. defaulted('minY', 0),
  12585. defaulted('maxY', 100),
  12586. customField('value', spec => Cell({
  12587. x: spec.mode.minX,
  12588. y: spec.mode.minY
  12589. })),
  12590. required$1('getInitialValue'),
  12591. output$1('manager', TwoDModel)
  12592. ]
  12593. })),
  12594. field('sliderBehaviours', [
  12595. Keying,
  12596. Representing
  12597. ]),
  12598. customField('mouseIsDown', () => Cell(false))
  12599. ];
  12600. const sketch$2 = (detail, components, _spec, _externals) => {
  12601. const getThumb = component => getPartOrDie(component, detail, 'thumb');
  12602. const getSpectrum = component => getPartOrDie(component, detail, 'spectrum');
  12603. const getLeftEdge = component => getPart(component, detail, 'left-edge');
  12604. const getRightEdge = component => getPart(component, detail, 'right-edge');
  12605. const getTopEdge = component => getPart(component, detail, 'top-edge');
  12606. const getBottomEdge = component => getPart(component, detail, 'bottom-edge');
  12607. const modelDetail = detail.model;
  12608. const model = modelDetail.manager;
  12609. const refresh = (slider, thumb) => {
  12610. model.setPositionFromValue(slider, thumb, detail, {
  12611. getLeftEdge,
  12612. getRightEdge,
  12613. getTopEdge,
  12614. getBottomEdge,
  12615. getSpectrum
  12616. });
  12617. };
  12618. const setValue = (slider, newValue) => {
  12619. modelDetail.value.set(newValue);
  12620. const thumb = getThumb(slider);
  12621. refresh(slider, thumb);
  12622. };
  12623. const changeValue = (slider, newValue) => {
  12624. setValue(slider, newValue);
  12625. const thumb = getThumb(slider);
  12626. detail.onChange(slider, thumb, newValue);
  12627. return Optional.some(true);
  12628. };
  12629. const resetToMin = slider => {
  12630. model.setToMin(slider, detail);
  12631. };
  12632. const resetToMax = slider => {
  12633. model.setToMax(slider, detail);
  12634. };
  12635. const choose = slider => {
  12636. const fireOnChoose = () => {
  12637. getPart(slider, detail, 'thumb').each(thumb => {
  12638. const value = modelDetail.value.get();
  12639. detail.onChoose(slider, thumb, value);
  12640. });
  12641. };
  12642. const wasDown = detail.mouseIsDown.get();
  12643. detail.mouseIsDown.set(false);
  12644. if (wasDown) {
  12645. fireOnChoose();
  12646. }
  12647. };
  12648. const onDragStart = (slider, simulatedEvent) => {
  12649. simulatedEvent.stop();
  12650. detail.mouseIsDown.set(true);
  12651. detail.onDragStart(slider, getThumb(slider));
  12652. };
  12653. const onDragEnd = (slider, simulatedEvent) => {
  12654. simulatedEvent.stop();
  12655. detail.onDragEnd(slider, getThumb(slider));
  12656. choose(slider);
  12657. };
  12658. return {
  12659. uid: detail.uid,
  12660. dom: detail.dom,
  12661. components,
  12662. behaviours: augment(detail.sliderBehaviours, [
  12663. Keying.config({
  12664. mode: 'special',
  12665. focusIn: slider => {
  12666. return getPart(slider, detail, 'spectrum').map(Keying.focusIn).map(always);
  12667. }
  12668. }),
  12669. Representing.config({
  12670. store: {
  12671. mode: 'manual',
  12672. getValue: _ => {
  12673. return modelDetail.value.get();
  12674. },
  12675. setValue
  12676. }
  12677. }),
  12678. Receiving.config({ channels: { [mouseReleased()]: { onReceive: choose } } })
  12679. ]),
  12680. events: derive$2([
  12681. run$1(sliderChangeEvent(), (slider, simulatedEvent) => {
  12682. changeValue(slider, simulatedEvent.event.value);
  12683. }),
  12684. runOnAttached((slider, _simulatedEvent) => {
  12685. const getInitial = modelDetail.getInitialValue();
  12686. modelDetail.value.set(getInitial);
  12687. const thumb = getThumb(slider);
  12688. refresh(slider, thumb);
  12689. const spectrum = getSpectrum(slider);
  12690. detail.onInit(slider, thumb, spectrum, modelDetail.value.get());
  12691. }),
  12692. run$1(touchstart(), onDragStart),
  12693. run$1(touchend(), onDragEnd),
  12694. run$1(mousedown(), onDragStart),
  12695. run$1(mouseup(), onDragEnd)
  12696. ]),
  12697. apis: {
  12698. resetToMin,
  12699. resetToMax,
  12700. setValue,
  12701. refresh
  12702. },
  12703. domModification: { styles: { position: 'relative' } }
  12704. };
  12705. };
  12706. const Slider = composite({
  12707. name: 'Slider',
  12708. configFields: SliderSchema,
  12709. partFields: SliderParts,
  12710. factory: sketch$2,
  12711. apis: {
  12712. setValue: (apis, slider, value) => {
  12713. apis.setValue(slider, value);
  12714. },
  12715. resetToMin: (apis, slider) => {
  12716. apis.resetToMin(slider);
  12717. },
  12718. resetToMax: (apis, slider) => {
  12719. apis.resetToMax(slider);
  12720. },
  12721. refresh: (apis, slider) => {
  12722. apis.refresh(slider);
  12723. }
  12724. }
  12725. });
  12726. const fieldsUpdate = generate$6('rgb-hex-update');
  12727. const sliderUpdate = generate$6('slider-update');
  12728. const paletteUpdate = generate$6('palette-update');
  12729. const sliderFactory = (translate, getClass) => {
  12730. const spectrum = Slider.parts.spectrum({
  12731. dom: {
  12732. tag: 'div',
  12733. classes: [getClass('hue-slider-spectrum')],
  12734. attributes: { role: 'presentation' }
  12735. }
  12736. });
  12737. const thumb = Slider.parts.thumb({
  12738. dom: {
  12739. tag: 'div',
  12740. classes: [getClass('hue-slider-thumb')],
  12741. attributes: { role: 'presentation' }
  12742. }
  12743. });
  12744. return Slider.sketch({
  12745. dom: {
  12746. tag: 'div',
  12747. classes: [getClass('hue-slider')],
  12748. attributes: { role: 'presentation' }
  12749. },
  12750. rounded: false,
  12751. model: {
  12752. mode: 'y',
  12753. getInitialValue: constant$1(0)
  12754. },
  12755. components: [
  12756. spectrum,
  12757. thumb
  12758. ],
  12759. sliderBehaviours: derive$1([Focusing.config({})]),
  12760. onChange: (slider, _thumb, value) => {
  12761. emitWith(slider, sliderUpdate, { value });
  12762. }
  12763. });
  12764. };
  12765. const owner$1 = 'form';
  12766. const schema$i = [field('formBehaviours', [Representing])];
  12767. const getPartName$1 = name => '<alloy.field.' + name + '>';
  12768. const sketch$1 = fSpec => {
  12769. const parts = (() => {
  12770. const record = [];
  12771. const field = (name, config) => {
  12772. record.push(name);
  12773. return generateOne$1(owner$1, getPartName$1(name), config);
  12774. };
  12775. return {
  12776. field,
  12777. record: constant$1(record)
  12778. };
  12779. })();
  12780. const spec = fSpec(parts);
  12781. const partNames = parts.record();
  12782. const fieldParts = map$2(partNames, n => required({
  12783. name: n,
  12784. pname: getPartName$1(n)
  12785. }));
  12786. return composite$1(owner$1, schema$i, fieldParts, make$4, spec);
  12787. };
  12788. const toResult = (o, e) => o.fold(() => Result.error(e), Result.value);
  12789. const make$4 = (detail, components) => ({
  12790. uid: detail.uid,
  12791. dom: detail.dom,
  12792. components,
  12793. behaviours: augment(detail.formBehaviours, [Representing.config({
  12794. store: {
  12795. mode: 'manual',
  12796. getValue: form => {
  12797. const resPs = getAllParts(form, detail);
  12798. return map$1(resPs, (resPThunk, pName) => resPThunk().bind(v => {
  12799. const opt = Composing.getCurrent(v);
  12800. return toResult(opt, new Error(`Cannot find a current component to extract the value from for form part '${ pName }': ` + element(v.element)));
  12801. }).map(Representing.getValue));
  12802. },
  12803. setValue: (form, values) => {
  12804. each(values, (newValue, key) => {
  12805. getPart(form, detail, key).each(wrapper => {
  12806. Composing.getCurrent(wrapper).each(field => {
  12807. Representing.setValue(field, newValue);
  12808. });
  12809. });
  12810. });
  12811. }
  12812. }
  12813. })]),
  12814. apis: {
  12815. getField: (form, key) => {
  12816. return getPart(form, detail, key).bind(Composing.getCurrent);
  12817. }
  12818. }
  12819. });
  12820. const Form = {
  12821. getField: makeApi((apis, component, key) => apis.getField(component, key)),
  12822. sketch: sketch$1
  12823. };
  12824. const validInput = generate$6('valid-input');
  12825. const invalidInput = generate$6('invalid-input');
  12826. const validatingInput = generate$6('validating-input');
  12827. const translatePrefix = 'colorcustom.rgb.';
  12828. const rgbFormFactory = (translate, getClass, onValidHexx, onInvalidHexx) => {
  12829. const invalidation = (label, isValid) => Invalidating.config({
  12830. invalidClass: getClass('invalid'),
  12831. notify: {
  12832. onValidate: comp => {
  12833. emitWith(comp, validatingInput, { type: label });
  12834. },
  12835. onValid: comp => {
  12836. emitWith(comp, validInput, {
  12837. type: label,
  12838. value: Representing.getValue(comp)
  12839. });
  12840. },
  12841. onInvalid: comp => {
  12842. emitWith(comp, invalidInput, {
  12843. type: label,
  12844. value: Representing.getValue(comp)
  12845. });
  12846. }
  12847. },
  12848. validator: {
  12849. validate: comp => {
  12850. const value = Representing.getValue(comp);
  12851. const res = isValid(value) ? Result.value(true) : Result.error(translate('aria.input.invalid'));
  12852. return Future.pure(res);
  12853. },
  12854. validateOnLoad: false
  12855. }
  12856. });
  12857. const renderTextField = (isValid, name, label, description, data) => {
  12858. const helptext = translate(translatePrefix + 'range');
  12859. const pLabel = FormField.parts.label({
  12860. dom: {
  12861. tag: 'label',
  12862. attributes: { 'aria-label': description }
  12863. },
  12864. components: [text$1(label)]
  12865. });
  12866. const pField = FormField.parts.field({
  12867. data,
  12868. factory: Input,
  12869. inputAttributes: {
  12870. type: 'text',
  12871. ...name === 'hex' ? { 'aria-live': 'polite' } : {}
  12872. },
  12873. inputClasses: [getClass('textfield')],
  12874. inputBehaviours: derive$1([
  12875. invalidation(name, isValid),
  12876. Tabstopping.config({})
  12877. ]),
  12878. onSetValue: input => {
  12879. if (Invalidating.isInvalid(input)) {
  12880. const run = Invalidating.run(input);
  12881. run.get(noop);
  12882. }
  12883. }
  12884. });
  12885. const comps = [
  12886. pLabel,
  12887. pField
  12888. ];
  12889. const concats = name !== 'hex' ? [FormField.parts['aria-descriptor']({ text: helptext })] : [];
  12890. const components = comps.concat(concats);
  12891. return {
  12892. dom: {
  12893. tag: 'div',
  12894. attributes: { role: 'presentation' }
  12895. },
  12896. components
  12897. };
  12898. };
  12899. const copyRgbToHex = (form, rgba) => {
  12900. const hex = fromRgba(rgba);
  12901. Form.getField(form, 'hex').each(hexField => {
  12902. if (!Focusing.isFocused(hexField)) {
  12903. Representing.setValue(form, { hex: hex.value });
  12904. }
  12905. });
  12906. return hex;
  12907. };
  12908. const copyRgbToForm = (form, rgb) => {
  12909. const red = rgb.red;
  12910. const green = rgb.green;
  12911. const blue = rgb.blue;
  12912. Representing.setValue(form, {
  12913. red,
  12914. green,
  12915. blue
  12916. });
  12917. };
  12918. const memPreview = record({
  12919. dom: {
  12920. tag: 'div',
  12921. classes: [getClass('rgba-preview')],
  12922. styles: { 'background-color': 'white' },
  12923. attributes: { role: 'presentation' }
  12924. }
  12925. });
  12926. const updatePreview = (anyInSystem, hex) => {
  12927. memPreview.getOpt(anyInSystem).each(preview => {
  12928. set$8(preview.element, 'background-color', '#' + hex.value);
  12929. });
  12930. };
  12931. const factory = () => {
  12932. const state = {
  12933. red: Cell(Optional.some(255)),
  12934. green: Cell(Optional.some(255)),
  12935. blue: Cell(Optional.some(255)),
  12936. hex: Cell(Optional.some('ffffff'))
  12937. };
  12938. const copyHexToRgb = (form, hex) => {
  12939. const rgb = fromHex(hex);
  12940. copyRgbToForm(form, rgb);
  12941. setValueRgb(rgb);
  12942. };
  12943. const get = prop => state[prop].get();
  12944. const set = (prop, value) => {
  12945. state[prop].set(value);
  12946. };
  12947. const getValueRgb = () => get('red').bind(red => get('green').bind(green => get('blue').map(blue => rgbaColour(red, green, blue, 1))));
  12948. const setValueRgb = rgb => {
  12949. const red = rgb.red;
  12950. const green = rgb.green;
  12951. const blue = rgb.blue;
  12952. set('red', Optional.some(red));
  12953. set('green', Optional.some(green));
  12954. set('blue', Optional.some(blue));
  12955. };
  12956. const onInvalidInput = (form, simulatedEvent) => {
  12957. const data = simulatedEvent.event;
  12958. if (data.type !== 'hex') {
  12959. set(data.type, Optional.none());
  12960. } else {
  12961. onInvalidHexx(form);
  12962. }
  12963. };
  12964. const onValidHex = (form, value) => {
  12965. onValidHexx(form);
  12966. const hex = hexColour(value);
  12967. set('hex', Optional.some(value));
  12968. const rgb = fromHex(hex);
  12969. copyRgbToForm(form, rgb);
  12970. setValueRgb(rgb);
  12971. emitWith(form, fieldsUpdate, { hex });
  12972. updatePreview(form, hex);
  12973. };
  12974. const onValidRgb = (form, prop, value) => {
  12975. const val = parseInt(value, 10);
  12976. set(prop, Optional.some(val));
  12977. getValueRgb().each(rgb => {
  12978. const hex = copyRgbToHex(form, rgb);
  12979. emitWith(form, fieldsUpdate, { hex });
  12980. updatePreview(form, hex);
  12981. });
  12982. };
  12983. const isHexInputEvent = data => data.type === 'hex';
  12984. const onValidInput = (form, simulatedEvent) => {
  12985. const data = simulatedEvent.event;
  12986. if (isHexInputEvent(data)) {
  12987. onValidHex(form, data.value);
  12988. } else {
  12989. onValidRgb(form, data.type, data.value);
  12990. }
  12991. };
  12992. const formPartStrings = key => ({
  12993. label: translate(translatePrefix + key + '.label'),
  12994. description: translate(translatePrefix + key + '.description')
  12995. });
  12996. const redStrings = formPartStrings('red');
  12997. const greenStrings = formPartStrings('green');
  12998. const blueStrings = formPartStrings('blue');
  12999. const hexStrings = formPartStrings('hex');
  13000. return deepMerge(Form.sketch(parts => ({
  13001. dom: {
  13002. tag: 'form',
  13003. classes: [getClass('rgb-form')],
  13004. attributes: { 'aria-label': translate('aria.color.picker') }
  13005. },
  13006. components: [
  13007. parts.field('red', FormField.sketch(renderTextField(isRgbaComponent, 'red', redStrings.label, redStrings.description, 255))),
  13008. parts.field('green', FormField.sketch(renderTextField(isRgbaComponent, 'green', greenStrings.label, greenStrings.description, 255))),
  13009. parts.field('blue', FormField.sketch(renderTextField(isRgbaComponent, 'blue', blueStrings.label, blueStrings.description, 255))),
  13010. parts.field('hex', FormField.sketch(renderTextField(isHexString, 'hex', hexStrings.label, hexStrings.description, 'ffffff'))),
  13011. memPreview.asSpec()
  13012. ],
  13013. formBehaviours: derive$1([
  13014. Invalidating.config({ invalidClass: getClass('form-invalid') }),
  13015. config('rgb-form-events', [
  13016. run$1(validInput, onValidInput),
  13017. run$1(invalidInput, onInvalidInput),
  13018. run$1(validatingInput, onInvalidInput)
  13019. ])
  13020. ])
  13021. })), {
  13022. apis: {
  13023. updateHex: (form, hex) => {
  13024. Representing.setValue(form, { hex: hex.value });
  13025. copyHexToRgb(form, hex);
  13026. updatePreview(form, hex);
  13027. }
  13028. }
  13029. });
  13030. };
  13031. const rgbFormSketcher = single({
  13032. factory,
  13033. name: 'RgbForm',
  13034. configFields: [],
  13035. apis: {
  13036. updateHex: (apis, form, hex) => {
  13037. apis.updateHex(form, hex);
  13038. }
  13039. },
  13040. extraApis: {}
  13041. });
  13042. return rgbFormSketcher;
  13043. };
  13044. const paletteFactory = (_translate, getClass) => {
  13045. const spectrumPart = Slider.parts.spectrum({
  13046. dom: {
  13047. tag: 'canvas',
  13048. attributes: { role: 'presentation' },
  13049. classes: [getClass('sv-palette-spectrum')]
  13050. }
  13051. });
  13052. const thumbPart = Slider.parts.thumb({
  13053. dom: {
  13054. tag: 'div',
  13055. attributes: { role: 'presentation' },
  13056. classes: [getClass('sv-palette-thumb')],
  13057. innerHtml: `<div class=${ getClass('sv-palette-inner-thumb') } role="presentation"></div>`
  13058. }
  13059. });
  13060. const setColour = (canvas, rgba) => {
  13061. const {width, height} = canvas;
  13062. const ctx = canvas.getContext('2d');
  13063. if (ctx === null) {
  13064. return;
  13065. }
  13066. ctx.fillStyle = rgba;
  13067. ctx.fillRect(0, 0, width, height);
  13068. const grdWhite = ctx.createLinearGradient(0, 0, width, 0);
  13069. grdWhite.addColorStop(0, 'rgba(255,255,255,1)');
  13070. grdWhite.addColorStop(1, 'rgba(255,255,255,0)');
  13071. ctx.fillStyle = grdWhite;
  13072. ctx.fillRect(0, 0, width, height);
  13073. const grdBlack = ctx.createLinearGradient(0, 0, 0, height);
  13074. grdBlack.addColorStop(0, 'rgba(0,0,0,0)');
  13075. grdBlack.addColorStop(1, 'rgba(0,0,0,1)');
  13076. ctx.fillStyle = grdBlack;
  13077. ctx.fillRect(0, 0, width, height);
  13078. };
  13079. const setPaletteHue = (slider, hue) => {
  13080. const canvas = slider.components()[0].element.dom;
  13081. const hsv = hsvColour(hue, 100, 100);
  13082. const rgba = fromHsv(hsv);
  13083. setColour(canvas, toString(rgba));
  13084. };
  13085. const setPaletteThumb = (slider, hex) => {
  13086. const hsv = fromRgb(fromHex(hex));
  13087. Slider.setValue(slider, {
  13088. x: hsv.saturation,
  13089. y: 100 - hsv.value
  13090. });
  13091. };
  13092. const factory = _detail => {
  13093. const getInitialValue = constant$1({
  13094. x: 0,
  13095. y: 0
  13096. });
  13097. const onChange = (slider, _thumb, value) => {
  13098. emitWith(slider, paletteUpdate, { value });
  13099. };
  13100. const onInit = (_slider, _thumb, spectrum, _value) => {
  13101. setColour(spectrum.element.dom, toString(red));
  13102. };
  13103. const sliderBehaviours = derive$1([
  13104. Composing.config({ find: Optional.some }),
  13105. Focusing.config({})
  13106. ]);
  13107. return Slider.sketch({
  13108. dom: {
  13109. tag: 'div',
  13110. attributes: { role: 'presentation' },
  13111. classes: [getClass('sv-palette')]
  13112. },
  13113. model: {
  13114. mode: 'xy',
  13115. getInitialValue
  13116. },
  13117. rounded: false,
  13118. components: [
  13119. spectrumPart,
  13120. thumbPart
  13121. ],
  13122. onChange,
  13123. onInit,
  13124. sliderBehaviours
  13125. });
  13126. };
  13127. const saturationBrightnessPaletteSketcher = single({
  13128. factory,
  13129. name: 'SaturationBrightnessPalette',
  13130. configFields: [],
  13131. apis: {
  13132. setHue: (_apis, slider, hue) => {
  13133. setPaletteHue(slider, hue);
  13134. },
  13135. setThumb: (_apis, slider, hex) => {
  13136. setPaletteThumb(slider, hex);
  13137. }
  13138. },
  13139. extraApis: {}
  13140. });
  13141. return saturationBrightnessPaletteSketcher;
  13142. };
  13143. const makeFactory = (translate, getClass) => {
  13144. const factory = detail => {
  13145. const rgbForm = rgbFormFactory(translate, getClass, detail.onValidHex, detail.onInvalidHex);
  13146. const sbPalette = paletteFactory(translate, getClass);
  13147. const hueSliderToDegrees = hue => (100 - hue) / 100 * 360;
  13148. const hueDegreesToSlider = hue => 100 - hue / 360 * 100;
  13149. const state = {
  13150. paletteRgba: Cell(red),
  13151. paletteHue: Cell(0)
  13152. };
  13153. const memSlider = record(sliderFactory(translate, getClass));
  13154. const memPalette = record(sbPalette.sketch({}));
  13155. const memRgb = record(rgbForm.sketch({}));
  13156. const updatePalette = (anyInSystem, _hex, hue) => {
  13157. memPalette.getOpt(anyInSystem).each(palette => {
  13158. sbPalette.setHue(palette, hue);
  13159. });
  13160. };
  13161. const updateFields = (anyInSystem, hex) => {
  13162. memRgb.getOpt(anyInSystem).each(form => {
  13163. rgbForm.updateHex(form, hex);
  13164. });
  13165. };
  13166. const updateSlider = (anyInSystem, _hex, hue) => {
  13167. memSlider.getOpt(anyInSystem).each(slider => {
  13168. Slider.setValue(slider, hueDegreesToSlider(hue));
  13169. });
  13170. };
  13171. const updatePaletteThumb = (anyInSystem, hex) => {
  13172. memPalette.getOpt(anyInSystem).each(palette => {
  13173. sbPalette.setThumb(palette, hex);
  13174. });
  13175. };
  13176. const updateState = (hex, hue) => {
  13177. const rgba = fromHex(hex);
  13178. state.paletteRgba.set(rgba);
  13179. state.paletteHue.set(hue);
  13180. };
  13181. const runUpdates = (anyInSystem, hex, hue, updates) => {
  13182. updateState(hex, hue);
  13183. each$1(updates, update => {
  13184. update(anyInSystem, hex, hue);
  13185. });
  13186. };
  13187. const onPaletteUpdate = () => {
  13188. const updates = [updateFields];
  13189. return (form, simulatedEvent) => {
  13190. const value = simulatedEvent.event.value;
  13191. const oldHue = state.paletteHue.get();
  13192. const newHsv = hsvColour(oldHue, value.x, 100 - value.y);
  13193. const newHex = hsvToHex(newHsv);
  13194. runUpdates(form, newHex, oldHue, updates);
  13195. };
  13196. };
  13197. const onSliderUpdate = () => {
  13198. const updates = [
  13199. updatePalette,
  13200. updateFields
  13201. ];
  13202. return (form, simulatedEvent) => {
  13203. const hue = hueSliderToDegrees(simulatedEvent.event.value);
  13204. const oldRgb = state.paletteRgba.get();
  13205. const oldHsv = fromRgb(oldRgb);
  13206. const newHsv = hsvColour(hue, oldHsv.saturation, oldHsv.value);
  13207. const newHex = hsvToHex(newHsv);
  13208. runUpdates(form, newHex, hue, updates);
  13209. };
  13210. };
  13211. const onFieldsUpdate = () => {
  13212. const updates = [
  13213. updatePalette,
  13214. updateSlider,
  13215. updatePaletteThumb
  13216. ];
  13217. return (form, simulatedEvent) => {
  13218. const hex = simulatedEvent.event.hex;
  13219. const hsv = hexToHsv(hex);
  13220. runUpdates(form, hex, hsv.hue, updates);
  13221. };
  13222. };
  13223. return {
  13224. uid: detail.uid,
  13225. dom: detail.dom,
  13226. components: [
  13227. memPalette.asSpec(),
  13228. memSlider.asSpec(),
  13229. memRgb.asSpec()
  13230. ],
  13231. behaviours: derive$1([
  13232. config('colour-picker-events', [
  13233. run$1(fieldsUpdate, onFieldsUpdate()),
  13234. run$1(paletteUpdate, onPaletteUpdate()),
  13235. run$1(sliderUpdate, onSliderUpdate())
  13236. ]),
  13237. Composing.config({ find: comp => memRgb.getOpt(comp) }),
  13238. Keying.config({ mode: 'acyclic' })
  13239. ])
  13240. };
  13241. };
  13242. const colourPickerSketcher = single({
  13243. name: 'ColourPicker',
  13244. configFields: [
  13245. required$1('dom'),
  13246. defaulted('onValidHex', noop),
  13247. defaulted('onInvalidHex', noop)
  13248. ],
  13249. factory
  13250. });
  13251. return colourPickerSketcher;
  13252. };
  13253. const self = () => Composing.config({ find: Optional.some });
  13254. const memento$1 = mem => Composing.config({ find: mem.getOpt });
  13255. const childAt = index => Composing.config({ find: comp => child$2(comp.element, index).bind(element => comp.getSystem().getByDom(element).toOptional()) });
  13256. const ComposingConfigs = {
  13257. self,
  13258. memento: memento$1,
  13259. childAt
  13260. };
  13261. const processors = objOf([
  13262. defaulted('preprocess', identity),
  13263. defaulted('postprocess', identity)
  13264. ]);
  13265. const memento = (mem, rawProcessors) => {
  13266. const ps = asRawOrDie$1('RepresentingConfigs.memento processors', processors, rawProcessors);
  13267. return Representing.config({
  13268. store: {
  13269. mode: 'manual',
  13270. getValue: comp => {
  13271. const other = mem.get(comp);
  13272. const rawValue = Representing.getValue(other);
  13273. return ps.postprocess(rawValue);
  13274. },
  13275. setValue: (comp, rawValue) => {
  13276. const newValue = ps.preprocess(rawValue);
  13277. const other = mem.get(comp);
  13278. Representing.setValue(other, newValue);
  13279. }
  13280. }
  13281. });
  13282. };
  13283. const withComp = (optInitialValue, getter, setter) => Representing.config({
  13284. store: {
  13285. mode: 'manual',
  13286. ...optInitialValue.map(initialValue => ({ initialValue })).getOr({}),
  13287. getValue: getter,
  13288. setValue: setter
  13289. }
  13290. });
  13291. const withElement = (initialValue, getter, setter) => withComp(initialValue, c => getter(c.element), (c, v) => setter(c.element, v));
  13292. const domValue = optInitialValue => withElement(optInitialValue, get$6, set$5);
  13293. const domHtml = optInitialValue => withElement(optInitialValue, get$9, set$6);
  13294. const memory = initialValue => Representing.config({
  13295. store: {
  13296. mode: 'memory',
  13297. initialValue
  13298. }
  13299. });
  13300. const RepresentingConfigs = {
  13301. memento,
  13302. withElement,
  13303. withComp,
  13304. domValue,
  13305. domHtml,
  13306. memory
  13307. };
  13308. const english = {
  13309. 'colorcustom.rgb.red.label': 'R',
  13310. 'colorcustom.rgb.red.description': 'Red component',
  13311. 'colorcustom.rgb.green.label': 'G',
  13312. 'colorcustom.rgb.green.description': 'Green component',
  13313. 'colorcustom.rgb.blue.label': 'B',
  13314. 'colorcustom.rgb.blue.description': 'Blue component',
  13315. 'colorcustom.rgb.hex.label': '#',
  13316. 'colorcustom.rgb.hex.description': 'Hex color code',
  13317. 'colorcustom.rgb.range': 'Range 0 to 255',
  13318. 'aria.color.picker': 'Color Picker',
  13319. 'aria.input.invalid': 'Invalid input'
  13320. };
  13321. const translate$1 = providerBackstage => key => {
  13322. return providerBackstage.translate(english[key]);
  13323. };
  13324. const renderColorPicker = (_spec, providerBackstage, initialData) => {
  13325. const getClass = key => 'tox-' + key;
  13326. const colourPickerFactory = makeFactory(translate$1(providerBackstage), getClass);
  13327. const onValidHex = form => {
  13328. emitWith(form, formActionEvent, {
  13329. name: 'hex-valid',
  13330. value: true
  13331. });
  13332. };
  13333. const onInvalidHex = form => {
  13334. emitWith(form, formActionEvent, {
  13335. name: 'hex-valid',
  13336. value: false
  13337. });
  13338. };
  13339. const memPicker = record(colourPickerFactory.sketch({
  13340. dom: {
  13341. tag: 'div',
  13342. classes: [getClass('color-picker-container')],
  13343. attributes: { role: 'presentation' }
  13344. },
  13345. onValidHex,
  13346. onInvalidHex
  13347. }));
  13348. return {
  13349. dom: { tag: 'div' },
  13350. components: [memPicker.asSpec()],
  13351. behaviours: derive$1([
  13352. RepresentingConfigs.withComp(initialData, comp => {
  13353. const picker = memPicker.get(comp);
  13354. const optRgbForm = Composing.getCurrent(picker);
  13355. const optHex = optRgbForm.bind(rgbForm => {
  13356. const formValues = Representing.getValue(rgbForm);
  13357. return formValues.hex;
  13358. });
  13359. return optHex.map(hex => '#' + hex).getOr('');
  13360. }, (comp, newValue) => {
  13361. const pattern = /^#([a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?)/;
  13362. const m = pattern.exec(newValue);
  13363. const picker = memPicker.get(comp);
  13364. const optRgbForm = Composing.getCurrent(picker);
  13365. optRgbForm.fold(() => {
  13366. console.log('Can not find form');
  13367. }, rgbForm => {
  13368. Representing.setValue(rgbForm, { hex: Optional.from(m[1]).getOr('') });
  13369. Form.getField(rgbForm, 'hex').each(hexField => {
  13370. emit(hexField, input());
  13371. });
  13372. });
  13373. }),
  13374. ComposingConfigs.self()
  13375. ])
  13376. };
  13377. };
  13378. var global$2 = tinymce.util.Tools.resolve('tinymce.Resource');
  13379. const isOldCustomEditor = spec => has$2(spec, 'init');
  13380. const renderCustomEditor = spec => {
  13381. const editorApi = value$2();
  13382. const memReplaced = record({ dom: { tag: spec.tag } });
  13383. const initialValue = value$2();
  13384. return {
  13385. dom: {
  13386. tag: 'div',
  13387. classes: ['tox-custom-editor']
  13388. },
  13389. behaviours: derive$1([
  13390. config('custom-editor-events', [runOnAttached(component => {
  13391. memReplaced.getOpt(component).each(ta => {
  13392. (isOldCustomEditor(spec) ? spec.init(ta.element.dom) : global$2.load(spec.scriptId, spec.scriptUrl).then(init => init(ta.element.dom, spec.settings))).then(ea => {
  13393. initialValue.on(cvalue => {
  13394. ea.setValue(cvalue);
  13395. });
  13396. initialValue.clear();
  13397. editorApi.set(ea);
  13398. });
  13399. });
  13400. })]),
  13401. RepresentingConfigs.withComp(Optional.none(), () => editorApi.get().fold(() => initialValue.get().getOr(''), ed => ed.getValue()), (component, value) => {
  13402. editorApi.get().fold(() => initialValue.set(value), ed => ed.setValue(value));
  13403. }),
  13404. ComposingConfigs.self()
  13405. ]),
  13406. components: [memReplaced.asSpec()]
  13407. };
  13408. };
  13409. var global$1 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  13410. const filterByExtension = (files, providersBackstage) => {
  13411. const allowedImageFileTypes = global$1.explode(providersBackstage.getOption('images_file_types'));
  13412. const isFileInAllowedTypes = file => exists(allowedImageFileTypes, type => endsWith(file.name.toLowerCase(), `.${ type.toLowerCase() }`));
  13413. return filter$2(from(files), isFileInAllowedTypes);
  13414. };
  13415. const renderDropZone = (spec, providersBackstage, initialData) => {
  13416. const stopper = (_, se) => {
  13417. se.stop();
  13418. };
  13419. const sequence = actions => (comp, se) => {
  13420. each$1(actions, a => {
  13421. a(comp, se);
  13422. });
  13423. };
  13424. const onDrop = (comp, se) => {
  13425. if (!Disabling.isDisabled(comp)) {
  13426. const transferEvent = se.event.raw;
  13427. handleFiles(comp, transferEvent.dataTransfer.files);
  13428. }
  13429. };
  13430. const onSelect = (component, simulatedEvent) => {
  13431. const input = simulatedEvent.event.raw.target;
  13432. handleFiles(component, input.files);
  13433. };
  13434. const handleFiles = (component, files) => {
  13435. Representing.setValue(component, filterByExtension(files, providersBackstage));
  13436. emitWith(component, formChangeEvent, { name: spec.name });
  13437. };
  13438. const memInput = record({
  13439. dom: {
  13440. tag: 'input',
  13441. attributes: {
  13442. type: 'file',
  13443. accept: 'image/*'
  13444. },
  13445. styles: { display: 'none' }
  13446. },
  13447. behaviours: derive$1([config('input-file-events', [
  13448. cutter(click()),
  13449. cutter(tap())
  13450. ])])
  13451. });
  13452. const renderField = s => ({
  13453. uid: s.uid,
  13454. dom: {
  13455. tag: 'div',
  13456. classes: ['tox-dropzone-container']
  13457. },
  13458. behaviours: derive$1([
  13459. RepresentingConfigs.memory(initialData.getOr([])),
  13460. ComposingConfigs.self(),
  13461. Disabling.config({}),
  13462. Toggling.config({
  13463. toggleClass: 'dragenter',
  13464. toggleOnExecute: false
  13465. }),
  13466. config('dropzone-events', [
  13467. run$1('dragenter', sequence([
  13468. stopper,
  13469. Toggling.toggle
  13470. ])),
  13471. run$1('dragleave', sequence([
  13472. stopper,
  13473. Toggling.toggle
  13474. ])),
  13475. run$1('dragover', stopper),
  13476. run$1('drop', sequence([
  13477. stopper,
  13478. onDrop
  13479. ])),
  13480. run$1(change(), onSelect)
  13481. ])
  13482. ]),
  13483. components: [{
  13484. dom: {
  13485. tag: 'div',
  13486. classes: ['tox-dropzone'],
  13487. styles: {}
  13488. },
  13489. components: [
  13490. {
  13491. dom: { tag: 'p' },
  13492. components: [text$1(providersBackstage.translate('Drop an image here'))]
  13493. },
  13494. Button.sketch({
  13495. dom: {
  13496. tag: 'button',
  13497. styles: { position: 'relative' },
  13498. classes: [
  13499. 'tox-button',
  13500. 'tox-button--secondary'
  13501. ]
  13502. },
  13503. components: [
  13504. text$1(providersBackstage.translate('Browse for an image')),
  13505. memInput.asSpec()
  13506. ],
  13507. action: comp => {
  13508. const inputComp = memInput.get(comp);
  13509. inputComp.element.dom.click();
  13510. },
  13511. buttonBehaviours: derive$1([
  13512. Tabstopping.config({}),
  13513. DisablingConfigs.button(providersBackstage.isDisabled),
  13514. receivingConfig()
  13515. ])
  13516. })
  13517. ]
  13518. }]
  13519. });
  13520. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  13521. const pField = FormField.parts.field({ factory: { sketch: renderField } });
  13522. return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
  13523. };
  13524. const renderGrid = (spec, backstage) => ({
  13525. dom: {
  13526. tag: 'div',
  13527. classes: [
  13528. 'tox-form__grid',
  13529. `tox-form__grid--${ spec.columns }col`
  13530. ]
  13531. },
  13532. components: map$2(spec.items, backstage.interpreter)
  13533. });
  13534. const beforeObject = generate$6('alloy-fake-before-tabstop');
  13535. const afterObject = generate$6('alloy-fake-after-tabstop');
  13536. const craftWithClasses = classes => {
  13537. return {
  13538. dom: {
  13539. tag: 'div',
  13540. styles: {
  13541. width: '1px',
  13542. height: '1px',
  13543. outline: 'none'
  13544. },
  13545. attributes: { tabindex: '0' },
  13546. classes
  13547. },
  13548. behaviours: derive$1([
  13549. Focusing.config({ ignore: true }),
  13550. Tabstopping.config({})
  13551. ])
  13552. };
  13553. };
  13554. const craft = spec => {
  13555. return {
  13556. dom: {
  13557. tag: 'div',
  13558. classes: ['tox-navobj']
  13559. },
  13560. components: [
  13561. craftWithClasses([beforeObject]),
  13562. spec,
  13563. craftWithClasses([afterObject])
  13564. ],
  13565. behaviours: derive$1([ComposingConfigs.childAt(1)])
  13566. };
  13567. };
  13568. const triggerTab = (placeholder, shiftKey) => {
  13569. emitWith(placeholder, keydown(), {
  13570. raw: {
  13571. which: 9,
  13572. shiftKey
  13573. }
  13574. });
  13575. };
  13576. const onFocus = (container, targetComp) => {
  13577. const target = targetComp.element;
  13578. if (has(target, beforeObject)) {
  13579. triggerTab(container, true);
  13580. } else if (has(target, afterObject)) {
  13581. triggerTab(container, false);
  13582. }
  13583. };
  13584. const isPseudoStop = element => {
  13585. return closest(element, [
  13586. '.' + beforeObject,
  13587. '.' + afterObject
  13588. ].join(','), never);
  13589. };
  13590. const getDynamicSource = initialData => {
  13591. const cachedValue = Cell(initialData.getOr(''));
  13592. return {
  13593. getValue: _frameComponent => cachedValue.get(),
  13594. setValue: (frameComponent, html) => {
  13595. if (cachedValue.get() !== html) {
  13596. set$9(frameComponent.element, 'srcdoc', html);
  13597. }
  13598. cachedValue.set(html);
  13599. }
  13600. };
  13601. };
  13602. const renderIFrame = (spec, providersBackstage, initialData) => {
  13603. const isSandbox = spec.sandboxed;
  13604. const isTransparent = spec.transparent;
  13605. const baseClass = 'tox-dialog__iframe';
  13606. const attributes = {
  13607. ...spec.label.map(title => ({ title })).getOr({}),
  13608. ...initialData.map(html => ({ srcdoc: html })).getOr({}),
  13609. ...isSandbox ? { sandbox: 'allow-scripts allow-same-origin' } : {}
  13610. };
  13611. const sourcing = getDynamicSource(initialData);
  13612. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  13613. const factory = newSpec => craft({
  13614. uid: newSpec.uid,
  13615. dom: {
  13616. tag: 'iframe',
  13617. attributes,
  13618. classes: isTransparent ? [baseClass] : [
  13619. baseClass,
  13620. `${ baseClass }--opaque`
  13621. ]
  13622. },
  13623. behaviours: derive$1([
  13624. Tabstopping.config({}),
  13625. Focusing.config({}),
  13626. RepresentingConfigs.withComp(initialData, sourcing.getValue, sourcing.setValue)
  13627. ])
  13628. });
  13629. const pField = FormField.parts.field({ factory: { sketch: factory } });
  13630. return renderFormFieldWith(pLabel, pField, ['tox-form__group--stretched'], []);
  13631. };
  13632. const image = image => new Promise((resolve, reject) => {
  13633. const loaded = () => {
  13634. destroy();
  13635. resolve(image);
  13636. };
  13637. const listeners = [
  13638. bind(image, 'load', loaded),
  13639. bind(image, 'error', () => {
  13640. destroy();
  13641. reject('Unable to load data from image: ' + image.dom.src);
  13642. })
  13643. ];
  13644. const destroy = () => each$1(listeners, l => l.unbind());
  13645. if (image.dom.complete) {
  13646. loaded();
  13647. }
  13648. });
  13649. const calculateImagePosition = (panelWidth, panelHeight, imageWidth, imageHeight, zoom) => {
  13650. const width = imageWidth * zoom;
  13651. const height = imageHeight * zoom;
  13652. const left = Math.max(0, panelWidth / 2 - width / 2);
  13653. const top = Math.max(0, panelHeight / 2 - height / 2);
  13654. return {
  13655. left: left.toString() + 'px',
  13656. top: top.toString() + 'px',
  13657. width: width.toString() + 'px',
  13658. height: height.toString() + 'px'
  13659. };
  13660. };
  13661. const zoomToFit = (panel, width, height) => {
  13662. const panelW = get$c(panel);
  13663. const panelH = get$d(panel);
  13664. return Math.min(panelW / width, panelH / height, 1);
  13665. };
  13666. const renderImagePreview = (spec, initialData) => {
  13667. const cachedData = Cell(initialData.getOr({ url: '' }));
  13668. const memImage = record({
  13669. dom: {
  13670. tag: 'img',
  13671. classes: ['tox-imagepreview__image'],
  13672. attributes: initialData.map(data => ({ src: data.url })).getOr({})
  13673. }
  13674. });
  13675. const memContainer = record({
  13676. dom: {
  13677. tag: 'div',
  13678. classes: ['tox-imagepreview__container'],
  13679. attributes: { role: 'presentation' }
  13680. },
  13681. components: [memImage.asSpec()]
  13682. });
  13683. const setValue = (frameComponent, data) => {
  13684. const translatedData = { url: data.url };
  13685. data.zoom.each(z => translatedData.zoom = z);
  13686. data.cachedWidth.each(z => translatedData.cachedWidth = z);
  13687. data.cachedHeight.each(z => translatedData.cachedHeight = z);
  13688. cachedData.set(translatedData);
  13689. const applyFramePositioning = () => {
  13690. const imageWidth = translatedData.cachedWidth;
  13691. const imageHeight = translatedData.cachedHeight;
  13692. if (isUndefined(translatedData.zoom)) {
  13693. const z = zoomToFit(frameComponent.element, imageWidth, imageHeight);
  13694. translatedData.zoom = z;
  13695. }
  13696. const position = calculateImagePosition(get$c(frameComponent.element), get$d(frameComponent.element), imageWidth, imageHeight, translatedData.zoom);
  13697. memContainer.getOpt(frameComponent).each(container => {
  13698. setAll(container.element, position);
  13699. });
  13700. };
  13701. memImage.getOpt(frameComponent).each(imageComponent => {
  13702. const img = imageComponent.element;
  13703. if (data.url !== get$f(img, 'src')) {
  13704. set$9(img, 'src', data.url);
  13705. remove$2(frameComponent.element, 'tox-imagepreview__loaded');
  13706. }
  13707. if (!isUndefined(translatedData.cachedWidth) && !isUndefined(translatedData.cachedHeight)) {
  13708. applyFramePositioning();
  13709. }
  13710. image(img).then(img => {
  13711. if (frameComponent.getSystem().isConnected()) {
  13712. add$2(frameComponent.element, 'tox-imagepreview__loaded');
  13713. translatedData.cachedWidth = img.dom.naturalWidth;
  13714. translatedData.cachedHeight = img.dom.naturalHeight;
  13715. applyFramePositioning();
  13716. }
  13717. });
  13718. });
  13719. };
  13720. const styles = {};
  13721. spec.height.each(h => styles.height = h);
  13722. const fakeValidatedData = initialData.map(d => ({
  13723. url: d.url,
  13724. zoom: Optional.from(d.zoom),
  13725. cachedWidth: Optional.from(d.cachedWidth),
  13726. cachedHeight: Optional.from(d.cachedHeight)
  13727. }));
  13728. return {
  13729. dom: {
  13730. tag: 'div',
  13731. classes: ['tox-imagepreview'],
  13732. styles,
  13733. attributes: { role: 'presentation' }
  13734. },
  13735. components: [memContainer.asSpec()],
  13736. behaviours: derive$1([
  13737. ComposingConfigs.self(),
  13738. RepresentingConfigs.withComp(fakeValidatedData, () => cachedData.get(), setValue)
  13739. ])
  13740. };
  13741. };
  13742. const renderLabel$1 = (spec, backstageShared) => {
  13743. const label = {
  13744. dom: {
  13745. tag: 'label',
  13746. classes: ['tox-label']
  13747. },
  13748. components: [text$1(backstageShared.providers.translate(spec.label))]
  13749. };
  13750. const comps = map$2(spec.items, backstageShared.interpreter);
  13751. return {
  13752. dom: {
  13753. tag: 'div',
  13754. classes: ['tox-form__group']
  13755. },
  13756. components: [
  13757. label,
  13758. ...comps
  13759. ],
  13760. behaviours: derive$1([
  13761. ComposingConfigs.self(),
  13762. Replacing.config({}),
  13763. RepresentingConfigs.domHtml(Optional.none()),
  13764. Keying.config({ mode: 'acyclic' })
  13765. ])
  13766. };
  13767. };
  13768. const internalToolbarButtonExecute = generate$6('toolbar.button.execute');
  13769. const onToolbarButtonExecute = info => runOnExecute$1((comp, _simulatedEvent) => {
  13770. runWithApi(info, comp)(itemApi => {
  13771. emitWith(comp, internalToolbarButtonExecute, { buttonApi: itemApi });
  13772. info.onAction(itemApi);
  13773. });
  13774. });
  13775. const toolbarButtonEventOrder = {
  13776. [execute$5()]: [
  13777. 'disabling',
  13778. 'alloy.base.behaviour',
  13779. 'toggling',
  13780. 'toolbar-button-events'
  13781. ]
  13782. };
  13783. const renderIcon = (iconName, iconsProvider, behaviours) => render$3(iconName, {
  13784. tag: 'span',
  13785. classes: [
  13786. 'tox-icon',
  13787. 'tox-tbtn__icon-wrap'
  13788. ],
  13789. behaviours
  13790. }, iconsProvider);
  13791. const renderIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, []);
  13792. const renderReplacableIconFromPack = (iconName, iconsProvider) => renderIcon(iconName, iconsProvider, [Replacing.config({})]);
  13793. const renderLabel = (text, prefix, providersBackstage) => ({
  13794. dom: {
  13795. tag: 'span',
  13796. classes: [`${ prefix }__select-label`]
  13797. },
  13798. components: [text$1(providersBackstage.translate(text))],
  13799. behaviours: derive$1([Replacing.config({})])
  13800. });
  13801. const updateMenuText = generate$6('update-menu-text');
  13802. const updateMenuIcon = generate$6('update-menu-icon');
  13803. const renderCommonDropdown = (spec, prefix, sharedBackstage) => {
  13804. const editorOffCell = Cell(noop);
  13805. const optMemDisplayText = spec.text.map(text => record(renderLabel(text, prefix, sharedBackstage.providers)));
  13806. const optMemDisplayIcon = spec.icon.map(iconName => record(renderReplacableIconFromPack(iconName, sharedBackstage.providers.icons)));
  13807. const onLeftOrRightInMenu = (comp, se) => {
  13808. const dropdown = Representing.getValue(comp);
  13809. Focusing.focus(dropdown);
  13810. emitWith(dropdown, 'keydown', { raw: se.event.raw });
  13811. Dropdown.close(dropdown);
  13812. return Optional.some(true);
  13813. };
  13814. const role = spec.role.fold(() => ({}), role => ({ role }));
  13815. const tooltipAttributes = spec.tooltip.fold(() => ({}), tooltip => {
  13816. const translatedTooltip = sharedBackstage.providers.translate(tooltip);
  13817. return {
  13818. 'title': translatedTooltip,
  13819. 'aria-label': translatedTooltip
  13820. };
  13821. });
  13822. const iconSpec = render$3('chevron-down', {
  13823. tag: 'div',
  13824. classes: [`${ prefix }__select-chevron`]
  13825. }, sharedBackstage.providers.icons);
  13826. const memDropdown = record(Dropdown.sketch({
  13827. ...spec.uid ? { uid: spec.uid } : {},
  13828. ...role,
  13829. dom: {
  13830. tag: 'button',
  13831. classes: [
  13832. prefix,
  13833. `${ prefix }--select`
  13834. ].concat(map$2(spec.classes, c => `${ prefix }--${ c }`)),
  13835. attributes: { ...tooltipAttributes }
  13836. },
  13837. components: componentRenderPipeline([
  13838. optMemDisplayIcon.map(mem => mem.asSpec()),
  13839. optMemDisplayText.map(mem => mem.asSpec()),
  13840. Optional.some(iconSpec)
  13841. ]),
  13842. matchWidth: true,
  13843. useMinWidth: true,
  13844. dropdownBehaviours: derive$1([
  13845. ...spec.dropdownBehaviours,
  13846. DisablingConfigs.button(() => spec.disabled || sharedBackstage.providers.isDisabled()),
  13847. receivingConfig(),
  13848. Unselecting.config({}),
  13849. Replacing.config({}),
  13850. config('dropdown-events', [
  13851. onControlAttached(spec, editorOffCell),
  13852. onControlDetached(spec, editorOffCell)
  13853. ]),
  13854. config('menubutton-update-display-text', [
  13855. run$1(updateMenuText, (comp, se) => {
  13856. optMemDisplayText.bind(mem => mem.getOpt(comp)).each(displayText => {
  13857. Replacing.set(displayText, [text$1(sharedBackstage.providers.translate(se.event.text))]);
  13858. });
  13859. }),
  13860. run$1(updateMenuIcon, (comp, se) => {
  13861. optMemDisplayIcon.bind(mem => mem.getOpt(comp)).each(displayIcon => {
  13862. Replacing.set(displayIcon, [renderReplacableIconFromPack(se.event.icon, sharedBackstage.providers.icons)]);
  13863. });
  13864. })
  13865. ])
  13866. ]),
  13867. eventOrder: deepMerge(toolbarButtonEventOrder, {
  13868. mousedown: [
  13869. 'focusing',
  13870. 'alloy.base.behaviour',
  13871. 'item-type-events',
  13872. 'normal-dropdown-events'
  13873. ]
  13874. }),
  13875. sandboxBehaviours: derive$1([Keying.config({
  13876. mode: 'special',
  13877. onLeft: onLeftOrRightInMenu,
  13878. onRight: onLeftOrRightInMenu
  13879. })]),
  13880. lazySink: sharedBackstage.getSink,
  13881. toggleClass: `${ prefix }--active`,
  13882. parts: { menu: part(false, spec.columns, spec.presets) },
  13883. fetch: comp => Future.nu(curry(spec.fetch, comp))
  13884. }));
  13885. return memDropdown.asSpec();
  13886. };
  13887. const isMenuItemReference = item => isString(item);
  13888. const isSeparator$1 = item => item.type === 'separator';
  13889. const isExpandingMenuItem = item => has$2(item, 'getSubmenuItems');
  13890. const separator$2 = { type: 'separator' };
  13891. const unwrapReferences = (items, menuItems) => {
  13892. const realItems = foldl(items, (acc, item) => {
  13893. if (isMenuItemReference(item)) {
  13894. if (item === '') {
  13895. return acc;
  13896. } else if (item === '|') {
  13897. return acc.length > 0 && !isSeparator$1(acc[acc.length - 1]) ? acc.concat([separator$2]) : acc;
  13898. } else if (has$2(menuItems, item.toLowerCase())) {
  13899. return acc.concat([menuItems[item.toLowerCase()]]);
  13900. } else {
  13901. return acc;
  13902. }
  13903. } else {
  13904. return acc.concat([item]);
  13905. }
  13906. }, []);
  13907. if (realItems.length > 0 && isSeparator$1(realItems[realItems.length - 1])) {
  13908. realItems.pop();
  13909. }
  13910. return realItems;
  13911. };
  13912. const getFromExpandingItem = (item, menuItems) => {
  13913. const submenuItems = item.getSubmenuItems();
  13914. const rest = expand(submenuItems, menuItems);
  13915. const newMenus = deepMerge(rest.menus, wrap$1(item.value, rest.items));
  13916. const newExpansions = deepMerge(rest.expansions, wrap$1(item.value, item.value));
  13917. return {
  13918. item,
  13919. menus: newMenus,
  13920. expansions: newExpansions
  13921. };
  13922. };
  13923. const getFromItem = (item, menuItems) => isExpandingMenuItem(item) ? getFromExpandingItem(item, menuItems) : {
  13924. item,
  13925. menus: {},
  13926. expansions: {}
  13927. };
  13928. const generateValueIfRequired = item => {
  13929. if (isSeparator$1(item)) {
  13930. return item;
  13931. } else {
  13932. const itemValue = get$g(item, 'value').getOrThunk(() => generate$6('generated-menu-item'));
  13933. return deepMerge({ value: itemValue }, item);
  13934. }
  13935. };
  13936. const expand = (items, menuItems) => {
  13937. const realItems = unwrapReferences(isString(items) ? items.split(' ') : items, menuItems);
  13938. return foldr(realItems, (acc, item) => {
  13939. const itemWithValue = generateValueIfRequired(item);
  13940. const newData = getFromItem(itemWithValue, menuItems);
  13941. return {
  13942. menus: deepMerge(acc.menus, newData.menus),
  13943. items: [newData.item].concat(acc.items),
  13944. expansions: deepMerge(acc.expansions, newData.expansions)
  13945. };
  13946. }, {
  13947. menus: {},
  13948. expansions: {},
  13949. items: []
  13950. });
  13951. };
  13952. const build = (items, itemResponse, backstage, isHorizontalMenu) => {
  13953. const primary = generate$6('primary-menu');
  13954. const data = expand(items, backstage.shared.providers.menuItems());
  13955. if (data.items.length === 0) {
  13956. return Optional.none();
  13957. }
  13958. const mainMenu = createPartialMenu(primary, data.items, itemResponse, backstage, isHorizontalMenu);
  13959. const submenus = map$1(data.menus, (menuItems, menuName) => createPartialMenu(menuName, menuItems, itemResponse, backstage, false));
  13960. const menus = deepMerge(submenus, wrap$1(primary, mainMenu));
  13961. return Optional.from(tieredMenu.tieredData(primary, menus, data.expansions));
  13962. };
  13963. const isSingleListItem = item => !has$2(item, 'items');
  13964. const dataAttribute = 'data-value';
  13965. const fetchItems = (dropdownComp, name, items, selectedValue) => map$2(items, item => {
  13966. if (!isSingleListItem(item)) {
  13967. return {
  13968. type: 'nestedmenuitem',
  13969. text: item.text,
  13970. getSubmenuItems: () => fetchItems(dropdownComp, name, item.items, selectedValue)
  13971. };
  13972. } else {
  13973. return {
  13974. type: 'togglemenuitem',
  13975. text: item.text,
  13976. value: item.value,
  13977. active: item.value === selectedValue,
  13978. onAction: () => {
  13979. Representing.setValue(dropdownComp, item.value);
  13980. emitWith(dropdownComp, formChangeEvent, { name });
  13981. Focusing.focus(dropdownComp);
  13982. }
  13983. };
  13984. }
  13985. });
  13986. const findItemByValue = (items, value) => findMap(items, item => {
  13987. if (!isSingleListItem(item)) {
  13988. return findItemByValue(item.items, value);
  13989. } else {
  13990. return someIf(item.value === value, item);
  13991. }
  13992. });
  13993. const renderListBox = (spec, backstage, initialData) => {
  13994. const providersBackstage = backstage.shared.providers;
  13995. const initialItem = initialData.bind(value => findItemByValue(spec.items, value)).orThunk(() => head(spec.items).filter(isSingleListItem));
  13996. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  13997. const pField = FormField.parts.field({
  13998. dom: {},
  13999. factory: {
  14000. sketch: sketchSpec => renderCommonDropdown({
  14001. uid: sketchSpec.uid,
  14002. text: initialItem.map(item => item.text),
  14003. icon: Optional.none(),
  14004. tooltip: spec.label,
  14005. role: Optional.none(),
  14006. fetch: (comp, callback) => {
  14007. const items = fetchItems(comp, spec.name, spec.items, Representing.getValue(comp));
  14008. callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false));
  14009. },
  14010. onSetup: constant$1(noop),
  14011. getApi: constant$1({}),
  14012. columns: 1,
  14013. presets: 'normal',
  14014. classes: [],
  14015. dropdownBehaviours: [
  14016. Tabstopping.config({}),
  14017. RepresentingConfigs.withComp(initialItem.map(item => item.value), comp => get$f(comp.element, dataAttribute), (comp, data) => {
  14018. findItemByValue(spec.items, data).each(item => {
  14019. set$9(comp.element, dataAttribute, item.value);
  14020. emitWith(comp, updateMenuText, { text: item.text });
  14021. });
  14022. })
  14023. ]
  14024. }, 'tox-listbox', backstage.shared)
  14025. }
  14026. });
  14027. const listBoxWrap = {
  14028. dom: {
  14029. tag: 'div',
  14030. classes: ['tox-listboxfield']
  14031. },
  14032. components: [pField]
  14033. };
  14034. return FormField.sketch({
  14035. dom: {
  14036. tag: 'div',
  14037. classes: ['tox-form__group']
  14038. },
  14039. components: flatten([
  14040. pLabel.toArray(),
  14041. [listBoxWrap]
  14042. ]),
  14043. fieldBehaviours: derive$1([Disabling.config({
  14044. disabled: constant$1(!spec.enabled),
  14045. onDisabled: comp => {
  14046. FormField.getField(comp).each(Disabling.disable);
  14047. },
  14048. onEnabled: comp => {
  14049. FormField.getField(comp).each(Disabling.enable);
  14050. }
  14051. })])
  14052. });
  14053. };
  14054. const renderPanel = (spec, backstage) => ({
  14055. dom: {
  14056. tag: 'div',
  14057. classes: spec.classes
  14058. },
  14059. components: map$2(spec.items, backstage.shared.interpreter)
  14060. });
  14061. const factory$f = (detail, _spec) => {
  14062. const options = map$2(detail.options, option => ({
  14063. dom: {
  14064. tag: 'option',
  14065. value: option.value,
  14066. innerHtml: option.text
  14067. }
  14068. }));
  14069. const initialValues = detail.data.map(v => wrap$1('initialValue', v)).getOr({});
  14070. return {
  14071. uid: detail.uid,
  14072. dom: {
  14073. tag: 'select',
  14074. classes: detail.selectClasses,
  14075. attributes: detail.selectAttributes
  14076. },
  14077. components: options,
  14078. behaviours: augment(detail.selectBehaviours, [
  14079. Focusing.config({}),
  14080. Representing.config({
  14081. store: {
  14082. mode: 'manual',
  14083. getValue: select => {
  14084. return get$6(select.element);
  14085. },
  14086. setValue: (select, newValue) => {
  14087. const found = find$5(detail.options, opt => opt.value === newValue);
  14088. if (found.isSome()) {
  14089. set$5(select.element, newValue);
  14090. }
  14091. },
  14092. ...initialValues
  14093. }
  14094. })
  14095. ])
  14096. };
  14097. };
  14098. const HtmlSelect = single({
  14099. name: 'HtmlSelect',
  14100. configFields: [
  14101. required$1('options'),
  14102. field('selectBehaviours', [
  14103. Focusing,
  14104. Representing
  14105. ]),
  14106. defaulted('selectClasses', []),
  14107. defaulted('selectAttributes', {}),
  14108. option$3('data')
  14109. ],
  14110. factory: factory$f
  14111. });
  14112. const renderSelectBox = (spec, providersBackstage, initialData) => {
  14113. const translatedOptions = map$2(spec.items, item => ({
  14114. text: providersBackstage.translate(item.text),
  14115. value: item.value
  14116. }));
  14117. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  14118. const pField = FormField.parts.field({
  14119. dom: {},
  14120. ...initialData.map(data => ({ data })).getOr({}),
  14121. selectAttributes: { size: spec.size },
  14122. options: translatedOptions,
  14123. factory: HtmlSelect,
  14124. selectBehaviours: derive$1([
  14125. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  14126. Tabstopping.config({}),
  14127. config('selectbox-change', [run$1(change(), (component, _) => {
  14128. emitWith(component, formChangeEvent, { name: spec.name });
  14129. })])
  14130. ])
  14131. });
  14132. const chevron = spec.size > 1 ? Optional.none() : Optional.some(render$3('chevron-down', {
  14133. tag: 'div',
  14134. classes: ['tox-selectfield__icon-js']
  14135. }, providersBackstage.icons));
  14136. const selectWrap = {
  14137. dom: {
  14138. tag: 'div',
  14139. classes: ['tox-selectfield']
  14140. },
  14141. components: flatten([
  14142. [pField],
  14143. chevron.toArray()
  14144. ])
  14145. };
  14146. return FormField.sketch({
  14147. dom: {
  14148. tag: 'div',
  14149. classes: ['tox-form__group']
  14150. },
  14151. components: flatten([
  14152. pLabel.toArray(),
  14153. [selectWrap]
  14154. ]),
  14155. fieldBehaviours: derive$1([
  14156. Disabling.config({
  14157. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  14158. onDisabled: comp => {
  14159. FormField.getField(comp).each(Disabling.disable);
  14160. },
  14161. onEnabled: comp => {
  14162. FormField.getField(comp).each(Disabling.enable);
  14163. }
  14164. }),
  14165. receivingConfig()
  14166. ])
  14167. });
  14168. };
  14169. const schema$h = constant$1([
  14170. defaulted('field1Name', 'field1'),
  14171. defaulted('field2Name', 'field2'),
  14172. onStrictHandler('onLockedChange'),
  14173. markers$1(['lockClass']),
  14174. defaulted('locked', false),
  14175. SketchBehaviours.field('coupledFieldBehaviours', [
  14176. Composing,
  14177. Representing
  14178. ])
  14179. ]);
  14180. const getField = (comp, detail, partName) => getPart(comp, detail, partName).bind(Composing.getCurrent);
  14181. const coupledPart = (selfName, otherName) => required({
  14182. factory: FormField,
  14183. name: selfName,
  14184. overrides: detail => {
  14185. return {
  14186. fieldBehaviours: derive$1([config('coupled-input-behaviour', [run$1(input(), me => {
  14187. getField(me, detail, otherName).each(other => {
  14188. getPart(me, detail, 'lock').each(lock => {
  14189. if (Toggling.isOn(lock)) {
  14190. detail.onLockedChange(me, other, lock);
  14191. }
  14192. });
  14193. });
  14194. })])])
  14195. };
  14196. }
  14197. });
  14198. const parts$c = constant$1([
  14199. coupledPart('field1', 'field2'),
  14200. coupledPart('field2', 'field1'),
  14201. required({
  14202. factory: Button,
  14203. schema: [required$1('dom')],
  14204. name: 'lock',
  14205. overrides: detail => {
  14206. return {
  14207. buttonBehaviours: derive$1([Toggling.config({
  14208. selected: detail.locked,
  14209. toggleClass: detail.markers.lockClass,
  14210. aria: { mode: 'pressed' }
  14211. })])
  14212. };
  14213. }
  14214. })
  14215. ]);
  14216. const factory$e = (detail, components, _spec, _externals) => ({
  14217. uid: detail.uid,
  14218. dom: detail.dom,
  14219. components,
  14220. behaviours: SketchBehaviours.augment(detail.coupledFieldBehaviours, [
  14221. Composing.config({ find: Optional.some }),
  14222. Representing.config({
  14223. store: {
  14224. mode: 'manual',
  14225. getValue: comp => {
  14226. const parts = getPartsOrDie(comp, detail, [
  14227. 'field1',
  14228. 'field2'
  14229. ]);
  14230. return {
  14231. [detail.field1Name]: Representing.getValue(parts.field1()),
  14232. [detail.field2Name]: Representing.getValue(parts.field2())
  14233. };
  14234. },
  14235. setValue: (comp, value) => {
  14236. const parts = getPartsOrDie(comp, detail, [
  14237. 'field1',
  14238. 'field2'
  14239. ]);
  14240. if (hasNonNullableKey(value, detail.field1Name)) {
  14241. Representing.setValue(parts.field1(), value[detail.field1Name]);
  14242. }
  14243. if (hasNonNullableKey(value, detail.field2Name)) {
  14244. Representing.setValue(parts.field2(), value[detail.field2Name]);
  14245. }
  14246. }
  14247. }
  14248. })
  14249. ]),
  14250. apis: {
  14251. getField1: component => getPart(component, detail, 'field1'),
  14252. getField2: component => getPart(component, detail, 'field2'),
  14253. getLock: component => getPart(component, detail, 'lock')
  14254. }
  14255. });
  14256. const FormCoupledInputs = composite({
  14257. name: 'FormCoupledInputs',
  14258. configFields: schema$h(),
  14259. partFields: parts$c(),
  14260. factory: factory$e,
  14261. apis: {
  14262. getField1: (apis, component) => apis.getField1(component),
  14263. getField2: (apis, component) => apis.getField2(component),
  14264. getLock: (apis, component) => apis.getLock(component)
  14265. }
  14266. });
  14267. const formatSize = size => {
  14268. const unitDec = {
  14269. '': 0,
  14270. 'px': 0,
  14271. 'pt': 1,
  14272. 'mm': 1,
  14273. 'pc': 2,
  14274. 'ex': 2,
  14275. 'em': 2,
  14276. 'ch': 2,
  14277. 'rem': 2,
  14278. 'cm': 3,
  14279. 'in': 4,
  14280. '%': 4
  14281. };
  14282. const maxDecimal = unit => unit in unitDec ? unitDec[unit] : 1;
  14283. let numText = size.value.toFixed(maxDecimal(size.unit));
  14284. if (numText.indexOf('.') !== -1) {
  14285. numText = numText.replace(/\.?0*$/, '');
  14286. }
  14287. return numText + size.unit;
  14288. };
  14289. const parseSize = sizeText => {
  14290. const numPattern = /^\s*(\d+(?:\.\d+)?)\s*(|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|%)\s*$/;
  14291. const match = numPattern.exec(sizeText);
  14292. if (match !== null) {
  14293. const value = parseFloat(match[1]);
  14294. const unit = match[2];
  14295. return Result.value({
  14296. value,
  14297. unit
  14298. });
  14299. } else {
  14300. return Result.error(sizeText);
  14301. }
  14302. };
  14303. const convertUnit = (size, unit) => {
  14304. const inInch = {
  14305. '': 96,
  14306. 'px': 96,
  14307. 'pt': 72,
  14308. 'cm': 2.54,
  14309. 'pc': 12,
  14310. 'mm': 25.4,
  14311. 'in': 1
  14312. };
  14313. const supported = u => has$2(inInch, u);
  14314. if (size.unit === unit) {
  14315. return Optional.some(size.value);
  14316. } else if (supported(size.unit) && supported(unit)) {
  14317. if (inInch[size.unit] === inInch[unit]) {
  14318. return Optional.some(size.value);
  14319. } else {
  14320. return Optional.some(size.value / inInch[size.unit] * inInch[unit]);
  14321. }
  14322. } else {
  14323. return Optional.none();
  14324. }
  14325. };
  14326. const noSizeConversion = _input => Optional.none();
  14327. const ratioSizeConversion = (scale, unit) => size => convertUnit(size, unit).map(value => ({
  14328. value: value * scale,
  14329. unit
  14330. }));
  14331. const makeRatioConverter = (currentFieldText, otherFieldText) => {
  14332. const cValue = parseSize(currentFieldText).toOptional();
  14333. const oValue = parseSize(otherFieldText).toOptional();
  14334. 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);
  14335. };
  14336. const renderSizeInput = (spec, providersBackstage) => {
  14337. let converter = noSizeConversion;
  14338. const ratioEvent = generate$6('ratio-event');
  14339. const makeIcon = iconName => render$3(iconName, {
  14340. tag: 'span',
  14341. classes: [
  14342. 'tox-icon',
  14343. 'tox-lock-icon__' + iconName
  14344. ]
  14345. }, providersBackstage.icons);
  14346. const pLock = FormCoupledInputs.parts.lock({
  14347. dom: {
  14348. tag: 'button',
  14349. classes: [
  14350. 'tox-lock',
  14351. 'tox-button',
  14352. 'tox-button--naked',
  14353. 'tox-button--icon'
  14354. ],
  14355. attributes: { title: providersBackstage.translate(spec.label.getOr('Constrain proportions')) }
  14356. },
  14357. components: [
  14358. makeIcon('lock'),
  14359. makeIcon('unlock')
  14360. ],
  14361. buttonBehaviours: derive$1([
  14362. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  14363. receivingConfig(),
  14364. Tabstopping.config({})
  14365. ])
  14366. });
  14367. const formGroup = components => ({
  14368. dom: {
  14369. tag: 'div',
  14370. classes: ['tox-form__group']
  14371. },
  14372. components
  14373. });
  14374. const getFieldPart = isField1 => FormField.parts.field({
  14375. factory: Input,
  14376. inputClasses: ['tox-textfield'],
  14377. inputBehaviours: derive$1([
  14378. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  14379. receivingConfig(),
  14380. Tabstopping.config({}),
  14381. config('size-input-events', [
  14382. run$1(focusin(), (component, _simulatedEvent) => {
  14383. emitWith(component, ratioEvent, { isField1 });
  14384. }),
  14385. run$1(change(), (component, _simulatedEvent) => {
  14386. emitWith(component, formChangeEvent, { name: spec.name });
  14387. })
  14388. ])
  14389. ]),
  14390. selectOnFocus: false
  14391. });
  14392. const getLabel = label => ({
  14393. dom: {
  14394. tag: 'label',
  14395. classes: ['tox-label']
  14396. },
  14397. components: [text$1(providersBackstage.translate(label))]
  14398. });
  14399. const widthField = FormCoupledInputs.parts.field1(formGroup([
  14400. FormField.parts.label(getLabel('Width')),
  14401. getFieldPart(true)
  14402. ]));
  14403. const heightField = FormCoupledInputs.parts.field2(formGroup([
  14404. FormField.parts.label(getLabel('Height')),
  14405. getFieldPart(false)
  14406. ]));
  14407. return FormCoupledInputs.sketch({
  14408. dom: {
  14409. tag: 'div',
  14410. classes: ['tox-form__group']
  14411. },
  14412. components: [{
  14413. dom: {
  14414. tag: 'div',
  14415. classes: ['tox-form__controls-h-stack']
  14416. },
  14417. components: [
  14418. widthField,
  14419. heightField,
  14420. formGroup([
  14421. getLabel(nbsp),
  14422. pLock
  14423. ])
  14424. ]
  14425. }],
  14426. field1Name: 'width',
  14427. field2Name: 'height',
  14428. locked: true,
  14429. markers: { lockClass: 'tox-locked' },
  14430. onLockedChange: (current, other, _lock) => {
  14431. parseSize(Representing.getValue(current)).each(size => {
  14432. converter(size).each(newSize => {
  14433. Representing.setValue(other, formatSize(newSize));
  14434. });
  14435. });
  14436. },
  14437. coupledFieldBehaviours: derive$1([
  14438. Disabling.config({
  14439. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  14440. onDisabled: comp => {
  14441. FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.disable);
  14442. FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.disable);
  14443. FormCoupledInputs.getLock(comp).each(Disabling.disable);
  14444. },
  14445. onEnabled: comp => {
  14446. FormCoupledInputs.getField1(comp).bind(FormField.getField).each(Disabling.enable);
  14447. FormCoupledInputs.getField2(comp).bind(FormField.getField).each(Disabling.enable);
  14448. FormCoupledInputs.getLock(comp).each(Disabling.enable);
  14449. }
  14450. }),
  14451. receivingConfig(),
  14452. config('size-input-events2', [run$1(ratioEvent, (component, simulatedEvent) => {
  14453. const isField1 = simulatedEvent.event.isField1;
  14454. const optCurrent = isField1 ? FormCoupledInputs.getField1(component) : FormCoupledInputs.getField2(component);
  14455. const optOther = isField1 ? FormCoupledInputs.getField2(component) : FormCoupledInputs.getField1(component);
  14456. const value1 = optCurrent.map(Representing.getValue).getOr('');
  14457. const value2 = optOther.map(Representing.getValue).getOr('');
  14458. converter = makeRatioConverter(value1, value2);
  14459. })])
  14460. ])
  14461. });
  14462. };
  14463. const renderSlider = (spec, providerBackstage, initialData) => {
  14464. const labelPart = Slider.parts.label({
  14465. dom: {
  14466. tag: 'label',
  14467. classes: ['tox-label']
  14468. },
  14469. components: [text$1(providerBackstage.translate(spec.label))]
  14470. });
  14471. const spectrum = Slider.parts.spectrum({
  14472. dom: {
  14473. tag: 'div',
  14474. classes: ['tox-slider__rail'],
  14475. attributes: { role: 'presentation' }
  14476. }
  14477. });
  14478. const thumb = Slider.parts.thumb({
  14479. dom: {
  14480. tag: 'div',
  14481. classes: ['tox-slider__handle'],
  14482. attributes: { role: 'presentation' }
  14483. }
  14484. });
  14485. return Slider.sketch({
  14486. dom: {
  14487. tag: 'div',
  14488. classes: ['tox-slider'],
  14489. attributes: { role: 'presentation' }
  14490. },
  14491. model: {
  14492. mode: 'x',
  14493. minX: spec.min,
  14494. maxX: spec.max,
  14495. getInitialValue: constant$1(initialData.getOrThunk(() => (Math.abs(spec.max) - Math.abs(spec.min)) / 2))
  14496. },
  14497. components: [
  14498. labelPart,
  14499. spectrum,
  14500. thumb
  14501. ],
  14502. sliderBehaviours: derive$1([
  14503. ComposingConfigs.self(),
  14504. Focusing.config({})
  14505. ]),
  14506. onChoose: (component, thumb, value) => {
  14507. emitWith(component, formChangeEvent, {
  14508. name: spec.name,
  14509. value
  14510. });
  14511. }
  14512. });
  14513. };
  14514. const renderTable = (spec, providersBackstage) => {
  14515. const renderTh = text => ({
  14516. dom: {
  14517. tag: 'th',
  14518. innerHtml: providersBackstage.translate(text)
  14519. }
  14520. });
  14521. const renderHeader = header => ({
  14522. dom: { tag: 'thead' },
  14523. components: [{
  14524. dom: { tag: 'tr' },
  14525. components: map$2(header, renderTh)
  14526. }]
  14527. });
  14528. const renderTd = text => ({
  14529. dom: {
  14530. tag: 'td',
  14531. innerHtml: providersBackstage.translate(text)
  14532. }
  14533. });
  14534. const renderTr = row => ({
  14535. dom: { tag: 'tr' },
  14536. components: map$2(row, renderTd)
  14537. });
  14538. const renderRows = rows => ({
  14539. dom: { tag: 'tbody' },
  14540. components: map$2(rows, renderTr)
  14541. });
  14542. return {
  14543. dom: {
  14544. tag: 'table',
  14545. classes: ['tox-dialog__table']
  14546. },
  14547. components: [
  14548. renderHeader(spec.header),
  14549. renderRows(spec.cells)
  14550. ],
  14551. behaviours: derive$1([
  14552. Tabstopping.config({}),
  14553. Focusing.config({})
  14554. ])
  14555. };
  14556. };
  14557. const renderTextField = (spec, providersBackstage) => {
  14558. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  14559. const baseInputBehaviours = [
  14560. Disabling.config({ disabled: () => spec.disabled || providersBackstage.isDisabled() }),
  14561. receivingConfig(),
  14562. Keying.config({
  14563. mode: 'execution',
  14564. useEnter: spec.multiline !== true,
  14565. useControlEnter: spec.multiline === true,
  14566. execute: comp => {
  14567. emit(comp, formSubmitEvent);
  14568. return Optional.some(true);
  14569. }
  14570. }),
  14571. config('textfield-change', [
  14572. run$1(input(), (component, _) => {
  14573. emitWith(component, formChangeEvent, { name: spec.name });
  14574. }),
  14575. run$1(postPaste(), (component, _) => {
  14576. emitWith(component, formChangeEvent, { name: spec.name });
  14577. })
  14578. ]),
  14579. Tabstopping.config({})
  14580. ];
  14581. const validatingBehaviours = spec.validation.map(vl => Invalidating.config({
  14582. getRoot: input => {
  14583. return parentElement(input.element);
  14584. },
  14585. invalidClass: 'tox-invalid',
  14586. validator: {
  14587. validate: input => {
  14588. const v = Representing.getValue(input);
  14589. const result = vl.validator(v);
  14590. return Future.pure(result === true ? Result.value(v) : Result.error(result));
  14591. },
  14592. validateOnLoad: vl.validateOnLoad
  14593. }
  14594. })).toArray();
  14595. const placeholder = spec.placeholder.fold(constant$1({}), p => ({ placeholder: providersBackstage.translate(p) }));
  14596. const inputMode = spec.inputMode.fold(constant$1({}), mode => ({ inputmode: mode }));
  14597. const inputAttributes = {
  14598. ...placeholder,
  14599. ...inputMode
  14600. };
  14601. const pField = FormField.parts.field({
  14602. tag: spec.multiline === true ? 'textarea' : 'input',
  14603. ...spec.data.map(data => ({ data })).getOr({}),
  14604. inputAttributes,
  14605. inputClasses: [spec.classname],
  14606. inputBehaviours: derive$1(flatten([
  14607. baseInputBehaviours,
  14608. validatingBehaviours
  14609. ])),
  14610. selectOnFocus: false,
  14611. factory: Input
  14612. });
  14613. const extraClasses = spec.flex ? ['tox-form__group--stretched'] : [];
  14614. const extraClasses2 = extraClasses.concat(spec.maximized ? ['tox-form-group--maximize'] : []);
  14615. const extraBehaviours = [
  14616. Disabling.config({
  14617. disabled: () => spec.disabled || providersBackstage.isDisabled(),
  14618. onDisabled: comp => {
  14619. FormField.getField(comp).each(Disabling.disable);
  14620. },
  14621. onEnabled: comp => {
  14622. FormField.getField(comp).each(Disabling.enable);
  14623. }
  14624. }),
  14625. receivingConfig()
  14626. ];
  14627. return renderFormFieldWith(pLabel, pField, extraClasses2, extraBehaviours);
  14628. };
  14629. const renderInput = (spec, providersBackstage, initialData) => renderTextField({
  14630. name: spec.name,
  14631. multiline: false,
  14632. label: spec.label,
  14633. inputMode: spec.inputMode,
  14634. placeholder: spec.placeholder,
  14635. flex: false,
  14636. disabled: !spec.enabled,
  14637. classname: 'tox-textfield',
  14638. validation: Optional.none(),
  14639. maximized: spec.maximized,
  14640. data: initialData
  14641. }, providersBackstage);
  14642. const renderTextarea = (spec, providersBackstage, initialData) => renderTextField({
  14643. name: spec.name,
  14644. multiline: true,
  14645. label: spec.label,
  14646. inputMode: Optional.none(),
  14647. placeholder: spec.placeholder,
  14648. flex: true,
  14649. disabled: !spec.enabled,
  14650. classname: 'tox-textarea',
  14651. validation: Optional.none(),
  14652. maximized: spec.maximized,
  14653. data: initialData
  14654. }, providersBackstage);
  14655. const events$6 = (streamConfig, streamState) => {
  14656. const streams = streamConfig.stream.streams;
  14657. const processor = streams.setup(streamConfig, streamState);
  14658. return derive$2([
  14659. run$1(streamConfig.event, processor),
  14660. runOnDetached(() => streamState.cancel())
  14661. ].concat(streamConfig.cancelEvent.map(e => [run$1(e, () => streamState.cancel())]).getOr([])));
  14662. };
  14663. var ActiveStreaming = /*#__PURE__*/Object.freeze({
  14664. __proto__: null,
  14665. events: events$6
  14666. });
  14667. const first = (fn, rate) => {
  14668. let timer = null;
  14669. const cancel = () => {
  14670. if (!isNull(timer)) {
  14671. clearTimeout(timer);
  14672. timer = null;
  14673. }
  14674. };
  14675. const throttle = (...args) => {
  14676. if (isNull(timer)) {
  14677. timer = setTimeout(() => {
  14678. timer = null;
  14679. fn.apply(null, args);
  14680. }, rate);
  14681. }
  14682. };
  14683. return {
  14684. cancel,
  14685. throttle
  14686. };
  14687. };
  14688. const last = (fn, rate) => {
  14689. let timer = null;
  14690. const cancel = () => {
  14691. if (!isNull(timer)) {
  14692. clearTimeout(timer);
  14693. timer = null;
  14694. }
  14695. };
  14696. const throttle = (...args) => {
  14697. cancel();
  14698. timer = setTimeout(() => {
  14699. timer = null;
  14700. fn.apply(null, args);
  14701. }, rate);
  14702. };
  14703. return {
  14704. cancel,
  14705. throttle
  14706. };
  14707. };
  14708. const throttle = _config => {
  14709. const state = Cell(null);
  14710. const readState = () => ({ timer: state.get() !== null ? 'set' : 'unset' });
  14711. const setTimer = t => {
  14712. state.set(t);
  14713. };
  14714. const cancel = () => {
  14715. const t = state.get();
  14716. if (t !== null) {
  14717. t.cancel();
  14718. }
  14719. };
  14720. return nu$8({
  14721. readState,
  14722. setTimer,
  14723. cancel
  14724. });
  14725. };
  14726. const init$9 = spec => spec.stream.streams.state(spec);
  14727. var StreamingState = /*#__PURE__*/Object.freeze({
  14728. __proto__: null,
  14729. throttle: throttle,
  14730. init: init$9
  14731. });
  14732. const setup$c = (streamInfo, streamState) => {
  14733. const sInfo = streamInfo.stream;
  14734. const throttler = last(streamInfo.onStream, sInfo.delay);
  14735. streamState.setTimer(throttler);
  14736. return (component, simulatedEvent) => {
  14737. throttler.throttle(component, simulatedEvent);
  14738. if (sInfo.stopEvent) {
  14739. simulatedEvent.stop();
  14740. }
  14741. };
  14742. };
  14743. var StreamingSchema = [
  14744. requiredOf('stream', choose$1('mode', {
  14745. throttle: [
  14746. required$1('delay'),
  14747. defaulted('stopEvent', true),
  14748. output$1('streams', {
  14749. setup: setup$c,
  14750. state: throttle
  14751. })
  14752. ]
  14753. })),
  14754. defaulted('event', 'input'),
  14755. option$3('cancelEvent'),
  14756. onStrictHandler('onStream')
  14757. ];
  14758. const Streaming = create$3({
  14759. fields: StreamingSchema,
  14760. name: 'streaming',
  14761. active: ActiveStreaming,
  14762. state: StreamingState
  14763. });
  14764. const setValueFromItem = (model, input, item) => {
  14765. const itemData = Representing.getValue(item);
  14766. Representing.setValue(input, itemData);
  14767. setCursorAtEnd(input);
  14768. };
  14769. const setSelectionOn = (input, f) => {
  14770. const el = input.element;
  14771. const value = get$6(el);
  14772. const node = el.dom;
  14773. if (get$f(el, 'type') !== 'number') {
  14774. f(node, value);
  14775. }
  14776. };
  14777. const setCursorAtEnd = input => {
  14778. setSelectionOn(input, (node, value) => node.setSelectionRange(value.length, value.length));
  14779. };
  14780. const setSelectionToEnd = (input, startOffset) => {
  14781. setSelectionOn(input, (node, value) => node.setSelectionRange(startOffset, value.length));
  14782. };
  14783. const attemptSelectOver = (model, input, item) => {
  14784. if (!model.selectsOver) {
  14785. return Optional.none();
  14786. } else {
  14787. const currentValue = Representing.getValue(input);
  14788. const inputDisplay = model.getDisplayText(currentValue);
  14789. const itemValue = Representing.getValue(item);
  14790. const itemDisplay = model.getDisplayText(itemValue);
  14791. return itemDisplay.indexOf(inputDisplay) === 0 ? Optional.some(() => {
  14792. setValueFromItem(model, input, item);
  14793. setSelectionToEnd(input, inputDisplay.length);
  14794. }) : Optional.none();
  14795. }
  14796. };
  14797. const itemExecute = constant$1('alloy.typeahead.itemexecute');
  14798. const make$3 = (detail, components, spec, externals) => {
  14799. const navigateList = (comp, simulatedEvent, highlighter) => {
  14800. detail.previewing.set(false);
  14801. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  14802. if (Sandboxing.isOpen(sandbox)) {
  14803. Composing.getCurrent(sandbox).each(menu => {
  14804. Highlighting.getHighlighted(menu).fold(() => {
  14805. highlighter(menu);
  14806. }, () => {
  14807. dispatchEvent(sandbox, menu.element, 'keydown', simulatedEvent);
  14808. });
  14809. });
  14810. } else {
  14811. const onOpenSync = sandbox => {
  14812. Composing.getCurrent(sandbox).each(highlighter);
  14813. };
  14814. open(detail, mapFetch(comp), comp, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
  14815. }
  14816. };
  14817. const focusBehaviours$1 = focusBehaviours(detail);
  14818. const mapFetch = comp => tdata => tdata.map(data => {
  14819. const menus = values(data.menus);
  14820. const items = bind$3(menus, menu => filter$2(menu.items, item => item.type === 'item'));
  14821. const repState = Representing.getState(comp);
  14822. repState.update(map$2(items, item => item.data));
  14823. return data;
  14824. });
  14825. const behaviours = [
  14826. Focusing.config({}),
  14827. Representing.config({
  14828. onSetValue: detail.onSetValue,
  14829. store: {
  14830. mode: 'dataset',
  14831. getDataKey: comp => get$6(comp.element),
  14832. getFallbackEntry: itemString => ({
  14833. value: itemString,
  14834. meta: {}
  14835. }),
  14836. setValue: (comp, data) => {
  14837. set$5(comp.element, detail.model.getDisplayText(data));
  14838. },
  14839. ...detail.initialData.map(d => wrap$1('initialValue', d)).getOr({})
  14840. }
  14841. }),
  14842. Streaming.config({
  14843. stream: {
  14844. mode: 'throttle',
  14845. delay: detail.responseTime,
  14846. stopEvent: false
  14847. },
  14848. onStream: (component, _simulatedEvent) => {
  14849. const sandbox = Coupling.getCoupled(component, 'sandbox');
  14850. const focusInInput = Focusing.isFocused(component);
  14851. if (focusInInput) {
  14852. if (get$6(component.element).length >= detail.minChars) {
  14853. const previousValue = Composing.getCurrent(sandbox).bind(menu => Highlighting.getHighlighted(menu).map(Representing.getValue));
  14854. detail.previewing.set(true);
  14855. const onOpenSync = _sandbox => {
  14856. Composing.getCurrent(sandbox).each(menu => {
  14857. previousValue.fold(() => {
  14858. if (detail.model.selectsOver) {
  14859. Highlighting.highlightFirst(menu);
  14860. }
  14861. }, pv => {
  14862. Highlighting.highlightBy(menu, item => {
  14863. const itemData = Representing.getValue(item);
  14864. return itemData.value === pv.value;
  14865. });
  14866. Highlighting.getHighlighted(menu).orThunk(() => {
  14867. Highlighting.highlightFirst(menu);
  14868. return Optional.none();
  14869. });
  14870. });
  14871. });
  14872. };
  14873. open(detail, mapFetch(component), component, sandbox, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
  14874. }
  14875. }
  14876. },
  14877. cancelEvent: typeaheadCancel()
  14878. }),
  14879. Keying.config({
  14880. mode: 'special',
  14881. onDown: (comp, simulatedEvent) => {
  14882. navigateList(comp, simulatedEvent, Highlighting.highlightFirst);
  14883. return Optional.some(true);
  14884. },
  14885. onEscape: comp => {
  14886. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  14887. if (Sandboxing.isOpen(sandbox)) {
  14888. Sandboxing.close(sandbox);
  14889. return Optional.some(true);
  14890. }
  14891. return Optional.none();
  14892. },
  14893. onUp: (comp, simulatedEvent) => {
  14894. navigateList(comp, simulatedEvent, Highlighting.highlightLast);
  14895. return Optional.some(true);
  14896. },
  14897. onEnter: comp => {
  14898. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  14899. const sandboxIsOpen = Sandboxing.isOpen(sandbox);
  14900. if (sandboxIsOpen && !detail.previewing.get()) {
  14901. return Composing.getCurrent(sandbox).bind(menu => Highlighting.getHighlighted(menu)).map(item => {
  14902. emitWith(comp, itemExecute(), { item });
  14903. return true;
  14904. });
  14905. } else {
  14906. const currentValue = Representing.getValue(comp);
  14907. emit(comp, typeaheadCancel());
  14908. detail.onExecute(sandbox, comp, currentValue);
  14909. if (sandboxIsOpen) {
  14910. Sandboxing.close(sandbox);
  14911. }
  14912. return Optional.some(true);
  14913. }
  14914. }
  14915. }),
  14916. Toggling.config({
  14917. toggleClass: detail.markers.openClass,
  14918. aria: { mode: 'expanded' }
  14919. }),
  14920. Coupling.config({
  14921. others: {
  14922. sandbox: hotspot => {
  14923. return makeSandbox$1(detail, hotspot, {
  14924. onOpen: () => Toggling.on(hotspot),
  14925. onClose: () => Toggling.off(hotspot)
  14926. });
  14927. }
  14928. }
  14929. }),
  14930. config('typeaheadevents', [
  14931. runOnExecute$1(comp => {
  14932. const onOpenSync = noop;
  14933. togglePopup(detail, mapFetch(comp), comp, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
  14934. }),
  14935. run$1(itemExecute(), (comp, se) => {
  14936. const sandbox = Coupling.getCoupled(comp, 'sandbox');
  14937. setValueFromItem(detail.model, comp, se.event.item);
  14938. emit(comp, typeaheadCancel());
  14939. detail.onItemExecute(comp, sandbox, se.event.item, Representing.getValue(comp));
  14940. Sandboxing.close(sandbox);
  14941. setCursorAtEnd(comp);
  14942. })
  14943. ].concat(detail.dismissOnBlur ? [run$1(postBlur(), typeahead => {
  14944. const sandbox = Coupling.getCoupled(typeahead, 'sandbox');
  14945. if (search(sandbox.element).isNone()) {
  14946. Sandboxing.close(sandbox);
  14947. }
  14948. })] : []))
  14949. ];
  14950. return {
  14951. uid: detail.uid,
  14952. dom: dom(deepMerge(detail, {
  14953. inputAttributes: {
  14954. 'role': 'combobox',
  14955. 'aria-autocomplete': 'list',
  14956. 'aria-haspopup': 'true'
  14957. }
  14958. })),
  14959. behaviours: {
  14960. ...focusBehaviours$1,
  14961. ...augment(detail.typeaheadBehaviours, behaviours)
  14962. },
  14963. eventOrder: detail.eventOrder
  14964. };
  14965. };
  14966. const schema$g = constant$1([
  14967. option$3('lazySink'),
  14968. required$1('fetch'),
  14969. defaulted('minChars', 5),
  14970. defaulted('responseTime', 1000),
  14971. onHandler('onOpen'),
  14972. defaulted('getHotspot', Optional.some),
  14973. defaulted('getAnchorOverrides', constant$1({})),
  14974. defaulted('layouts', Optional.none()),
  14975. defaulted('eventOrder', {}),
  14976. defaultedObjOf('model', {}, [
  14977. defaulted('getDisplayText', itemData => itemData.meta !== undefined && itemData.meta.text !== undefined ? itemData.meta.text : itemData.value),
  14978. defaulted('selectsOver', true),
  14979. defaulted('populateFromBrowse', true)
  14980. ]),
  14981. onHandler('onSetValue'),
  14982. onKeyboardHandler('onExecute'),
  14983. onHandler('onItemExecute'),
  14984. defaulted('inputClasses', []),
  14985. defaulted('inputAttributes', {}),
  14986. defaulted('inputStyles', {}),
  14987. defaulted('matchWidth', true),
  14988. defaulted('useMinWidth', false),
  14989. defaulted('dismissOnBlur', true),
  14990. markers$1(['openClass']),
  14991. option$3('initialData'),
  14992. field('typeaheadBehaviours', [
  14993. Focusing,
  14994. Representing,
  14995. Streaming,
  14996. Keying,
  14997. Toggling,
  14998. Coupling
  14999. ]),
  15000. customField('previewing', () => Cell(true))
  15001. ].concat(schema$k()).concat(sandboxFields()));
  15002. const parts$b = constant$1([external({
  15003. schema: [tieredMenuMarkers()],
  15004. name: 'menu',
  15005. overrides: detail => {
  15006. return {
  15007. fakeFocus: true,
  15008. onHighlight: (menu, item) => {
  15009. if (!detail.previewing.get()) {
  15010. menu.getSystem().getByUid(detail.uid).each(input => {
  15011. if (detail.model.populateFromBrowse) {
  15012. setValueFromItem(detail.model, input, item);
  15013. }
  15014. });
  15015. } else {
  15016. menu.getSystem().getByUid(detail.uid).each(input => {
  15017. attemptSelectOver(detail.model, input, item).fold(() => Highlighting.dehighlight(menu, item), fn => fn());
  15018. });
  15019. }
  15020. detail.previewing.set(false);
  15021. },
  15022. onExecute: (menu, item) => {
  15023. return menu.getSystem().getByUid(detail.uid).toOptional().map(typeahead => {
  15024. emitWith(typeahead, itemExecute(), { item });
  15025. return true;
  15026. });
  15027. },
  15028. onHover: (menu, item) => {
  15029. detail.previewing.set(false);
  15030. menu.getSystem().getByUid(detail.uid).each(input => {
  15031. if (detail.model.populateFromBrowse) {
  15032. setValueFromItem(detail.model, input, item);
  15033. }
  15034. });
  15035. }
  15036. };
  15037. }
  15038. })]);
  15039. const Typeahead = composite({
  15040. name: 'Typeahead',
  15041. configFields: schema$g(),
  15042. partFields: parts$b(),
  15043. factory: make$3
  15044. });
  15045. const wrap = delegate => {
  15046. const toCached = () => {
  15047. return wrap(delegate.toCached());
  15048. };
  15049. const bindFuture = f => {
  15050. return wrap(delegate.bind(resA => resA.fold(err => Future.pure(Result.error(err)), a => f(a))));
  15051. };
  15052. const bindResult = f => {
  15053. return wrap(delegate.map(resA => resA.bind(f)));
  15054. };
  15055. const mapResult = f => {
  15056. return wrap(delegate.map(resA => resA.map(f)));
  15057. };
  15058. const mapError = f => {
  15059. return wrap(delegate.map(resA => resA.mapError(f)));
  15060. };
  15061. const foldResult = (whenError, whenValue) => {
  15062. return delegate.map(res => res.fold(whenError, whenValue));
  15063. };
  15064. const withTimeout = (timeout, errorThunk) => {
  15065. return wrap(Future.nu(callback => {
  15066. let timedOut = false;
  15067. const timer = setTimeout(() => {
  15068. timedOut = true;
  15069. callback(Result.error(errorThunk()));
  15070. }, timeout);
  15071. delegate.get(result => {
  15072. if (!timedOut) {
  15073. clearTimeout(timer);
  15074. callback(result);
  15075. }
  15076. });
  15077. }));
  15078. };
  15079. return {
  15080. ...delegate,
  15081. toCached,
  15082. bindFuture,
  15083. bindResult,
  15084. mapResult,
  15085. mapError,
  15086. foldResult,
  15087. withTimeout
  15088. };
  15089. };
  15090. const nu$1 = worker => {
  15091. return wrap(Future.nu(worker));
  15092. };
  15093. const value = value => {
  15094. return wrap(Future.pure(Result.value(value)));
  15095. };
  15096. const error = error => {
  15097. return wrap(Future.pure(Result.error(error)));
  15098. };
  15099. const fromResult = result => {
  15100. return wrap(Future.pure(result));
  15101. };
  15102. const fromFuture = future => {
  15103. return wrap(future.map(Result.value));
  15104. };
  15105. const fromPromise = promise => {
  15106. return nu$1(completer => {
  15107. promise.then(value => {
  15108. completer(Result.value(value));
  15109. }, error => {
  15110. completer(Result.error(error));
  15111. });
  15112. });
  15113. };
  15114. const FutureResult = {
  15115. nu: nu$1,
  15116. wrap,
  15117. pure: value,
  15118. value,
  15119. error,
  15120. fromResult,
  15121. fromFuture,
  15122. fromPromise
  15123. };
  15124. const getMenuButtonApi = component => ({
  15125. isEnabled: () => !Disabling.isDisabled(component),
  15126. setEnabled: state => Disabling.set(component, !state),
  15127. setActive: state => {
  15128. const elm = component.element;
  15129. if (state) {
  15130. add$2(elm, 'tox-tbtn--enabled');
  15131. set$9(elm, 'aria-pressed', true);
  15132. } else {
  15133. remove$2(elm, 'tox-tbtn--enabled');
  15134. remove$7(elm, 'aria-pressed');
  15135. }
  15136. },
  15137. isActive: () => has(component.element, 'tox-tbtn--enabled')
  15138. });
  15139. const renderMenuButton = (spec, prefix, backstage, role) => renderCommonDropdown({
  15140. text: spec.text,
  15141. icon: spec.icon,
  15142. tooltip: spec.tooltip,
  15143. role,
  15144. fetch: (_comp, callback) => {
  15145. spec.fetch(items => {
  15146. callback(build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false));
  15147. });
  15148. },
  15149. onSetup: spec.onSetup,
  15150. getApi: getMenuButtonApi,
  15151. columns: 1,
  15152. presets: 'normal',
  15153. classes: [],
  15154. dropdownBehaviours: [Tabstopping.config({})]
  15155. }, prefix, backstage.shared);
  15156. const getFetch = (items, getButton, backstage) => {
  15157. const getMenuItemAction = item => api => {
  15158. const newValue = !api.isActive();
  15159. api.setActive(newValue);
  15160. item.storage.set(newValue);
  15161. backstage.shared.getSink().each(sink => {
  15162. getButton().getOpt(sink).each(orig => {
  15163. focus$3(orig.element);
  15164. emitWith(orig, formActionEvent, {
  15165. name: item.name,
  15166. value: item.storage.get()
  15167. });
  15168. });
  15169. });
  15170. };
  15171. const getMenuItemSetup = item => api => {
  15172. api.setActive(item.storage.get());
  15173. };
  15174. return success => {
  15175. success(map$2(items, item => {
  15176. const text = item.text.fold(() => ({}), text => ({ text }));
  15177. return {
  15178. type: item.type,
  15179. active: false,
  15180. ...text,
  15181. onAction: getMenuItemAction(item),
  15182. onSetup: getMenuItemSetup(item)
  15183. };
  15184. }));
  15185. };
  15186. };
  15187. const renderCommonSpec = (spec, actionOpt, extraBehaviours = [], dom, components, providersBackstage) => {
  15188. const action = actionOpt.fold(() => ({}), action => ({ action }));
  15189. const common = {
  15190. buttonBehaviours: derive$1([
  15191. DisablingConfigs.button(() => !spec.enabled || providersBackstage.isDisabled()),
  15192. receivingConfig(),
  15193. Tabstopping.config({}),
  15194. config('button press', [
  15195. preventDefault('click'),
  15196. preventDefault('mousedown')
  15197. ])
  15198. ].concat(extraBehaviours)),
  15199. eventOrder: {
  15200. click: [
  15201. 'button press',
  15202. 'alloy.base.behaviour'
  15203. ],
  15204. mousedown: [
  15205. 'button press',
  15206. 'alloy.base.behaviour'
  15207. ]
  15208. },
  15209. ...action
  15210. };
  15211. const domFinal = deepMerge(common, { dom });
  15212. return deepMerge(domFinal, { components });
  15213. };
  15214. const renderIconButtonSpec = (spec, action, providersBackstage, extraBehaviours = []) => {
  15215. const tooltipAttributes = spec.tooltip.map(tooltip => ({
  15216. 'aria-label': providersBackstage.translate(tooltip),
  15217. 'title': providersBackstage.translate(tooltip)
  15218. })).getOr({});
  15219. const dom = {
  15220. tag: 'button',
  15221. classes: ['tox-tbtn'],
  15222. attributes: tooltipAttributes
  15223. };
  15224. const icon = spec.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons));
  15225. const components = componentRenderPipeline([icon]);
  15226. return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
  15227. };
  15228. const calculateClassesFromButtonType = buttonType => {
  15229. switch (buttonType) {
  15230. case 'primary':
  15231. return ['tox-button'];
  15232. case 'toolbar':
  15233. return ['tox-tbtn'];
  15234. case 'secondary':
  15235. default:
  15236. return [
  15237. 'tox-button',
  15238. 'tox-button--secondary'
  15239. ];
  15240. }
  15241. };
  15242. const renderButtonSpec = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
  15243. const translatedText = providersBackstage.translate(spec.text);
  15244. const icon = spec.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons));
  15245. const components = [icon.getOrThunk(() => text$1(translatedText))];
  15246. const buttonType = spec.buttonType.getOr(!spec.primary && !spec.borderless ? 'secondary' : 'primary');
  15247. const baseClasses = calculateClassesFromButtonType(buttonType);
  15248. const classes = [
  15249. ...baseClasses,
  15250. ...icon.isSome() ? ['tox-button--icon'] : [],
  15251. ...spec.borderless ? ['tox-button--naked'] : [],
  15252. ...extraClasses
  15253. ];
  15254. const dom = {
  15255. tag: 'button',
  15256. classes,
  15257. attributes: { title: translatedText }
  15258. };
  15259. return renderCommonSpec(spec, action, extraBehaviours, dom, components, providersBackstage);
  15260. };
  15261. const renderButton = (spec, action, providersBackstage, extraBehaviours = [], extraClasses = []) => {
  15262. const buttonSpec = renderButtonSpec(spec, Optional.some(action), providersBackstage, extraBehaviours, extraClasses);
  15263. return Button.sketch(buttonSpec);
  15264. };
  15265. const getAction = (name, buttonType) => comp => {
  15266. if (buttonType === 'custom') {
  15267. emitWith(comp, formActionEvent, {
  15268. name,
  15269. value: {}
  15270. });
  15271. } else if (buttonType === 'submit') {
  15272. emit(comp, formSubmitEvent);
  15273. } else if (buttonType === 'cancel') {
  15274. emit(comp, formCancelEvent);
  15275. } else {
  15276. console.error('Unknown button type: ', buttonType);
  15277. }
  15278. };
  15279. const isMenuFooterButtonSpec = (spec, buttonType) => buttonType === 'menu';
  15280. const isNormalFooterButtonSpec = (spec, buttonType) => buttonType === 'custom' || buttonType === 'cancel' || buttonType === 'submit';
  15281. const renderFooterButton = (spec, buttonType, backstage) => {
  15282. if (isMenuFooterButtonSpec(spec, buttonType)) {
  15283. const getButton = () => memButton;
  15284. const menuButtonSpec = spec;
  15285. const fixedSpec = {
  15286. ...spec,
  15287. onSetup: api => {
  15288. api.setEnabled(spec.enabled);
  15289. return noop;
  15290. },
  15291. fetch: getFetch(menuButtonSpec.items, getButton, backstage)
  15292. };
  15293. const memButton = record(renderMenuButton(fixedSpec, 'tox-tbtn', backstage, Optional.none()));
  15294. return memButton.asSpec();
  15295. } else if (isNormalFooterButtonSpec(spec, buttonType)) {
  15296. const action = getAction(spec.name, buttonType);
  15297. const buttonSpec = {
  15298. ...spec,
  15299. borderless: false
  15300. };
  15301. return renderButton(buttonSpec, action, backstage.shared.providers, []);
  15302. } else {
  15303. console.error('Unknown footer button type: ', buttonType);
  15304. }
  15305. };
  15306. const renderDialogButton = (spec, providersBackstage) => {
  15307. const action = getAction(spec.name, 'custom');
  15308. return renderFormField(Optional.none(), FormField.parts.field({
  15309. factory: Button,
  15310. ...renderButtonSpec(spec, Optional.some(action), providersBackstage, [
  15311. RepresentingConfigs.memory(''),
  15312. ComposingConfigs.self()
  15313. ])
  15314. }));
  15315. };
  15316. const separator$1 = { type: 'separator' };
  15317. const toMenuItem = target => ({
  15318. type: 'menuitem',
  15319. value: target.url,
  15320. text: target.title,
  15321. meta: { attach: target.attach },
  15322. onAction: noop
  15323. });
  15324. const staticMenuItem = (title, url) => ({
  15325. type: 'menuitem',
  15326. value: url,
  15327. text: title,
  15328. meta: { attach: undefined },
  15329. onAction: noop
  15330. });
  15331. const toMenuItems = targets => map$2(targets, toMenuItem);
  15332. const filterLinkTargets = (type, targets) => filter$2(targets, target => target.type === type);
  15333. const filteredTargets = (type, targets) => toMenuItems(filterLinkTargets(type, targets));
  15334. const headerTargets = linkInfo => filteredTargets('header', linkInfo.targets);
  15335. const anchorTargets = linkInfo => filteredTargets('anchor', linkInfo.targets);
  15336. const anchorTargetTop = linkInfo => Optional.from(linkInfo.anchorTop).map(url => staticMenuItem('<top>', url)).toArray();
  15337. const anchorTargetBottom = linkInfo => Optional.from(linkInfo.anchorBottom).map(url => staticMenuItem('<bottom>', url)).toArray();
  15338. const historyTargets = history => map$2(history, url => staticMenuItem(url, url));
  15339. const joinMenuLists = items => {
  15340. return foldl(items, (a, b) => {
  15341. const bothEmpty = a.length === 0 || b.length === 0;
  15342. return bothEmpty ? a.concat(b) : a.concat(separator$1, b);
  15343. }, []);
  15344. };
  15345. const filterByQuery = (term, menuItems) => {
  15346. const lowerCaseTerm = term.toLowerCase();
  15347. return filter$2(menuItems, item => {
  15348. const text = item.meta !== undefined && item.meta.text !== undefined ? item.meta.text : item.text;
  15349. return contains$1(text.toLowerCase(), lowerCaseTerm) || contains$1(item.value.toLowerCase(), lowerCaseTerm);
  15350. });
  15351. };
  15352. const getItems = (fileType, input, urlBackstage) => {
  15353. const urlInputValue = Representing.getValue(input);
  15354. const term = urlInputValue.meta.text !== undefined ? urlInputValue.meta.text : urlInputValue.value;
  15355. const info = urlBackstage.getLinkInformation();
  15356. return info.fold(() => [], linkInfo => {
  15357. const history = filterByQuery(term, historyTargets(urlBackstage.getHistory(fileType)));
  15358. return fileType === 'file' ? joinMenuLists([
  15359. history,
  15360. filterByQuery(term, headerTargets(linkInfo)),
  15361. filterByQuery(term, flatten([
  15362. anchorTargetTop(linkInfo),
  15363. anchorTargets(linkInfo),
  15364. anchorTargetBottom(linkInfo)
  15365. ]))
  15366. ]) : history;
  15367. });
  15368. };
  15369. const errorId = generate$6('aria-invalid');
  15370. const renderUrlInput = (spec, backstage, urlBackstage, initialData) => {
  15371. const providersBackstage = backstage.shared.providers;
  15372. const updateHistory = component => {
  15373. const urlEntry = Representing.getValue(component);
  15374. urlBackstage.addToHistory(urlEntry.value, spec.filetype);
  15375. };
  15376. const pField = FormField.parts.field({
  15377. factory: Typeahead,
  15378. ...initialData.map(initialData => ({ initialData })).getOr({}),
  15379. dismissOnBlur: true,
  15380. inputClasses: ['tox-textfield'],
  15381. sandboxClasses: ['tox-dialog__popups'],
  15382. inputAttributes: {
  15383. 'aria-errormessage': errorId,
  15384. 'type': 'url'
  15385. },
  15386. minChars: 0,
  15387. responseTime: 0,
  15388. fetch: input => {
  15389. const items = getItems(spec.filetype, input, urlBackstage);
  15390. const tdata = build(items, ItemResponse$1.BUBBLE_TO_SANDBOX, backstage, false);
  15391. return Future.pure(tdata);
  15392. },
  15393. getHotspot: comp => memUrlBox.getOpt(comp),
  15394. onSetValue: (comp, _newValue) => {
  15395. if (comp.hasConfigured(Invalidating)) {
  15396. Invalidating.run(comp).get(noop);
  15397. }
  15398. },
  15399. typeaheadBehaviours: derive$1(flatten([
  15400. urlBackstage.getValidationHandler().map(handler => Invalidating.config({
  15401. getRoot: comp => parentElement(comp.element),
  15402. invalidClass: 'tox-control-wrap--status-invalid',
  15403. notify: {
  15404. onInvalid: (comp, err) => {
  15405. memInvalidIcon.getOpt(comp).each(invalidComp => {
  15406. set$9(invalidComp.element, 'title', providersBackstage.translate(err));
  15407. });
  15408. }
  15409. },
  15410. validator: {
  15411. validate: input => {
  15412. const urlEntry = Representing.getValue(input);
  15413. return FutureResult.nu(completer => {
  15414. handler({
  15415. type: spec.filetype,
  15416. url: urlEntry.value
  15417. }, validation => {
  15418. if (validation.status === 'invalid') {
  15419. const err = Result.error(validation.message);
  15420. completer(err);
  15421. } else {
  15422. const val = Result.value(validation.message);
  15423. completer(val);
  15424. }
  15425. });
  15426. });
  15427. },
  15428. validateOnLoad: false
  15429. }
  15430. })).toArray(),
  15431. [
  15432. Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() }),
  15433. Tabstopping.config({}),
  15434. config('urlinput-events', flatten([
  15435. spec.filetype === 'file' ? [run$1(input(), comp => {
  15436. emitWith(comp, formChangeEvent, { name: spec.name });
  15437. })] : [],
  15438. [
  15439. run$1(change(), comp => {
  15440. emitWith(comp, formChangeEvent, { name: spec.name });
  15441. updateHistory(comp);
  15442. }),
  15443. run$1(postPaste(), comp => {
  15444. emitWith(comp, formChangeEvent, { name: spec.name });
  15445. updateHistory(comp);
  15446. })
  15447. ]
  15448. ]))
  15449. ]
  15450. ])),
  15451. eventOrder: {
  15452. [input()]: [
  15453. 'streaming',
  15454. 'urlinput-events',
  15455. 'invalidating'
  15456. ]
  15457. },
  15458. model: {
  15459. getDisplayText: itemData => itemData.value,
  15460. selectsOver: false,
  15461. populateFromBrowse: false
  15462. },
  15463. markers: { openClass: 'tox-textfield--popup-open' },
  15464. lazySink: backstage.shared.getSink,
  15465. parts: { menu: part(false, 1, 'normal') },
  15466. onExecute: (_menu, component, _entry) => {
  15467. emitWith(component, formSubmitEvent, {});
  15468. },
  15469. onItemExecute: (typeahead, _sandbox, _item, _value) => {
  15470. updateHistory(typeahead);
  15471. emitWith(typeahead, formChangeEvent, { name: spec.name });
  15472. }
  15473. });
  15474. const pLabel = spec.label.map(label => renderLabel$2(label, providersBackstage));
  15475. const makeIcon = (name, errId, icon = name, label = name) => render$3(icon, {
  15476. tag: 'div',
  15477. classes: [
  15478. 'tox-icon',
  15479. 'tox-control-wrap__status-icon-' + name
  15480. ],
  15481. attributes: {
  15482. 'title': providersBackstage.translate(label),
  15483. 'aria-live': 'polite',
  15484. ...errId.fold(() => ({}), id => ({ id }))
  15485. }
  15486. }, providersBackstage.icons);
  15487. const memInvalidIcon = record(makeIcon('invalid', Optional.some(errorId), 'warning'));
  15488. const memStatus = record({
  15489. dom: {
  15490. tag: 'div',
  15491. classes: ['tox-control-wrap__status-icon-wrap']
  15492. },
  15493. components: [memInvalidIcon.asSpec()]
  15494. });
  15495. const optUrlPicker = urlBackstage.getUrlPicker(spec.filetype);
  15496. const browseUrlEvent = generate$6('browser.url.event');
  15497. const memUrlBox = record({
  15498. dom: {
  15499. tag: 'div',
  15500. classes: ['tox-control-wrap']
  15501. },
  15502. components: [
  15503. pField,
  15504. memStatus.asSpec()
  15505. ],
  15506. behaviours: derive$1([Disabling.config({ disabled: () => !spec.enabled || providersBackstage.isDisabled() })])
  15507. });
  15508. const memUrlPickerButton = record(renderButton({
  15509. name: spec.name,
  15510. icon: Optional.some('browse'),
  15511. text: spec.label.getOr(''),
  15512. enabled: spec.enabled,
  15513. primary: false,
  15514. buttonType: Optional.none(),
  15515. borderless: true
  15516. }, component => emit(component, browseUrlEvent), providersBackstage, [], ['tox-browse-url']));
  15517. const controlHWrapper = () => ({
  15518. dom: {
  15519. tag: 'div',
  15520. classes: ['tox-form__controls-h-stack']
  15521. },
  15522. components: flatten([
  15523. [memUrlBox.asSpec()],
  15524. optUrlPicker.map(() => memUrlPickerButton.asSpec()).toArray()
  15525. ])
  15526. });
  15527. const openUrlPicker = comp => {
  15528. Composing.getCurrent(comp).each(field => {
  15529. const componentData = Representing.getValue(field);
  15530. const urlData = {
  15531. fieldname: spec.name,
  15532. ...componentData
  15533. };
  15534. optUrlPicker.each(picker => {
  15535. picker(urlData).get(chosenData => {
  15536. Representing.setValue(field, chosenData);
  15537. emitWith(comp, formChangeEvent, { name: spec.name });
  15538. });
  15539. });
  15540. });
  15541. };
  15542. return FormField.sketch({
  15543. dom: renderFormFieldDom(),
  15544. components: pLabel.toArray().concat([controlHWrapper()]),
  15545. fieldBehaviours: derive$1([
  15546. Disabling.config({
  15547. disabled: () => !spec.enabled || providersBackstage.isDisabled(),
  15548. onDisabled: comp => {
  15549. FormField.getField(comp).each(Disabling.disable);
  15550. memUrlPickerButton.getOpt(comp).each(Disabling.disable);
  15551. },
  15552. onEnabled: comp => {
  15553. FormField.getField(comp).each(Disabling.enable);
  15554. memUrlPickerButton.getOpt(comp).each(Disabling.enable);
  15555. }
  15556. }),
  15557. receivingConfig(),
  15558. config('url-input-events', [run$1(browseUrlEvent, openUrlPicker)])
  15559. ])
  15560. });
  15561. };
  15562. const renderAlertBanner = (spec, providersBackstage) => Container.sketch({
  15563. dom: {
  15564. tag: 'div',
  15565. attributes: { role: 'alert' },
  15566. classes: [
  15567. 'tox-notification',
  15568. 'tox-notification--in',
  15569. `tox-notification--${ spec.level }`
  15570. ]
  15571. },
  15572. components: [
  15573. {
  15574. dom: {
  15575. tag: 'div',
  15576. classes: ['tox-notification__icon']
  15577. },
  15578. components: [Button.sketch({
  15579. dom: {
  15580. tag: 'button',
  15581. classes: [
  15582. 'tox-button',
  15583. 'tox-button--naked',
  15584. 'tox-button--icon'
  15585. ],
  15586. innerHtml: get$2(spec.icon, providersBackstage.icons),
  15587. attributes: { title: providersBackstage.translate(spec.iconTooltip) }
  15588. },
  15589. action: comp => {
  15590. emitWith(comp, formActionEvent, {
  15591. name: 'alert-banner',
  15592. value: spec.url
  15593. });
  15594. },
  15595. buttonBehaviours: derive$1([addFocusableBehaviour()])
  15596. })]
  15597. },
  15598. {
  15599. dom: {
  15600. tag: 'div',
  15601. classes: ['tox-notification__body'],
  15602. innerHtml: providersBackstage.translate(spec.text)
  15603. }
  15604. }
  15605. ]
  15606. });
  15607. const set$1 = (element, status) => {
  15608. element.dom.checked = status;
  15609. };
  15610. const get$1 = element => element.dom.checked;
  15611. const renderCheckbox = (spec, providerBackstage, initialData) => {
  15612. const toggleCheckboxHandler = comp => {
  15613. comp.element.dom.click();
  15614. return Optional.some(true);
  15615. };
  15616. const pField = FormField.parts.field({
  15617. factory: { sketch: identity },
  15618. dom: {
  15619. tag: 'input',
  15620. classes: ['tox-checkbox__input'],
  15621. attributes: { type: 'checkbox' }
  15622. },
  15623. behaviours: derive$1([
  15624. ComposingConfigs.self(),
  15625. Disabling.config({ disabled: () => !spec.enabled || providerBackstage.isDisabled() }),
  15626. Tabstopping.config({}),
  15627. Focusing.config({}),
  15628. RepresentingConfigs.withElement(initialData, get$1, set$1),
  15629. Keying.config({
  15630. mode: 'special',
  15631. onEnter: toggleCheckboxHandler,
  15632. onSpace: toggleCheckboxHandler,
  15633. stopSpaceKeyup: true
  15634. }),
  15635. config('checkbox-events', [run$1(change(), (component, _) => {
  15636. emitWith(component, formChangeEvent, { name: spec.name });
  15637. })])
  15638. ])
  15639. });
  15640. const pLabel = FormField.parts.label({
  15641. dom: {
  15642. tag: 'span',
  15643. classes: ['tox-checkbox__label']
  15644. },
  15645. components: [text$1(providerBackstage.translate(spec.label))],
  15646. behaviours: derive$1([Unselecting.config({})])
  15647. });
  15648. const makeIcon = className => {
  15649. const iconName = className === 'checked' ? 'selected' : 'unselected';
  15650. return render$3(iconName, {
  15651. tag: 'span',
  15652. classes: [
  15653. 'tox-icon',
  15654. 'tox-checkbox-icon__' + className
  15655. ]
  15656. }, providerBackstage.icons);
  15657. };
  15658. const memIcons = record({
  15659. dom: {
  15660. tag: 'div',
  15661. classes: ['tox-checkbox__icons']
  15662. },
  15663. components: [
  15664. makeIcon('checked'),
  15665. makeIcon('unchecked')
  15666. ]
  15667. });
  15668. return FormField.sketch({
  15669. dom: {
  15670. tag: 'label',
  15671. classes: ['tox-checkbox']
  15672. },
  15673. components: [
  15674. pField,
  15675. memIcons.asSpec(),
  15676. pLabel
  15677. ],
  15678. fieldBehaviours: derive$1([
  15679. Disabling.config({
  15680. disabled: () => !spec.enabled || providerBackstage.isDisabled(),
  15681. disableClass: 'tox-checkbox--disabled',
  15682. onDisabled: comp => {
  15683. FormField.getField(comp).each(Disabling.disable);
  15684. },
  15685. onEnabled: comp => {
  15686. FormField.getField(comp).each(Disabling.enable);
  15687. }
  15688. }),
  15689. receivingConfig()
  15690. ])
  15691. });
  15692. };
  15693. const renderHtmlPanel = spec => {
  15694. if (spec.presets === 'presentation') {
  15695. return Container.sketch({
  15696. dom: {
  15697. tag: 'div',
  15698. classes: ['tox-form__group'],
  15699. innerHtml: spec.html
  15700. }
  15701. });
  15702. } else {
  15703. return Container.sketch({
  15704. dom: {
  15705. tag: 'div',
  15706. classes: ['tox-form__group'],
  15707. innerHtml: spec.html,
  15708. attributes: { role: 'document' }
  15709. },
  15710. containerBehaviours: derive$1([
  15711. Tabstopping.config({}),
  15712. Focusing.config({})
  15713. ])
  15714. });
  15715. }
  15716. };
  15717. const make$2 = render => {
  15718. 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))));
  15719. };
  15720. const makeIframe = render => (parts, spec, dialogData, backstage) => {
  15721. const iframeSpec = deepMerge(spec, { source: 'dynamic' });
  15722. return make$2(render)(parts, iframeSpec, dialogData, backstage);
  15723. };
  15724. const factories = {
  15725. bar: make$2((spec, backstage) => renderBar(spec, backstage.shared)),
  15726. collection: make$2((spec, backstage, data) => renderCollection(spec, backstage.shared.providers, data)),
  15727. alertbanner: make$2((spec, backstage) => renderAlertBanner(spec, backstage.shared.providers)),
  15728. input: make$2((spec, backstage, data) => renderInput(spec, backstage.shared.providers, data)),
  15729. textarea: make$2((spec, backstage, data) => renderTextarea(spec, backstage.shared.providers, data)),
  15730. label: make$2((spec, backstage) => renderLabel$1(spec, backstage.shared)),
  15731. iframe: makeIframe((spec, backstage, data) => renderIFrame(spec, backstage.shared.providers, data)),
  15732. button: make$2((spec, backstage) => renderDialogButton(spec, backstage.shared.providers)),
  15733. checkbox: make$2((spec, backstage, data) => renderCheckbox(spec, backstage.shared.providers, data)),
  15734. colorinput: make$2((spec, backstage, data) => renderColorInput(spec, backstage.shared, backstage.colorinput, data)),
  15735. colorpicker: make$2((spec, backstage, data) => renderColorPicker(spec, backstage.shared.providers, data)),
  15736. dropzone: make$2((spec, backstage, data) => renderDropZone(spec, backstage.shared.providers, data)),
  15737. grid: make$2((spec, backstage) => renderGrid(spec, backstage.shared)),
  15738. listbox: make$2((spec, backstage, data) => renderListBox(spec, backstage, data)),
  15739. selectbox: make$2((spec, backstage, data) => renderSelectBox(spec, backstage.shared.providers, data)),
  15740. sizeinput: make$2((spec, backstage) => renderSizeInput(spec, backstage.shared.providers)),
  15741. slider: make$2((spec, backstage, data) => renderSlider(spec, backstage.shared.providers, data)),
  15742. urlinput: make$2((spec, backstage, data) => renderUrlInput(spec, backstage, backstage.urlinput, data)),
  15743. customeditor: make$2(renderCustomEditor),
  15744. htmlpanel: make$2(renderHtmlPanel),
  15745. imagepreview: make$2((spec, _, data) => renderImagePreview(spec, data)),
  15746. table: make$2((spec, backstage) => renderTable(spec, backstage.shared.providers)),
  15747. panel: make$2((spec, backstage) => renderPanel(spec, backstage))
  15748. };
  15749. const noFormParts = {
  15750. field: (_name, spec) => spec,
  15751. record: constant$1([])
  15752. };
  15753. const interpretInForm = (parts, spec, dialogData, oldBackstage) => {
  15754. const newBackstage = deepMerge(oldBackstage, { shared: { interpreter: childSpec => interpretParts(parts, childSpec, dialogData, newBackstage) } });
  15755. return interpretParts(parts, spec, dialogData, newBackstage);
  15756. };
  15757. const interpretParts = (parts, spec, dialogData, backstage) => get$g(factories, spec.type).fold(() => {
  15758. console.error(`Unknown factory type "${ spec.type }", defaulting to container: `, spec);
  15759. return spec;
  15760. }, factory => factory(parts, spec, dialogData, backstage));
  15761. const interpretWithoutForm = (spec, dialogData, backstage) => interpretParts(noFormParts, spec, dialogData, backstage);
  15762. const labelPrefix = 'layout-inset';
  15763. const westEdgeX = anchor => anchor.x;
  15764. const middleX = (anchor, element) => anchor.x + anchor.width / 2 - element.width / 2;
  15765. const eastEdgeX = (anchor, element) => anchor.x + anchor.width - element.width;
  15766. const northY = anchor => anchor.y;
  15767. const southY = (anchor, element) => anchor.y + anchor.height - element.height;
  15768. const centreY = (anchor, element) => anchor.y + anchor.height / 2 - element.height / 2;
  15769. const southwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), southY(anchor, element), bubbles.insetSouthwest(), northwest$3(), 'southwest', boundsRestriction(anchor, {
  15770. right: 0,
  15771. bottom: 3
  15772. }), labelPrefix);
  15773. const southeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), southY(anchor, element), bubbles.insetSoutheast(), northeast$3(), 'southeast', boundsRestriction(anchor, {
  15774. left: 1,
  15775. bottom: 3
  15776. }), labelPrefix);
  15777. const northwest = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), northY(anchor), bubbles.insetNorthwest(), southwest$3(), 'northwest', boundsRestriction(anchor, {
  15778. right: 0,
  15779. top: 2
  15780. }), labelPrefix);
  15781. const northeast = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), northY(anchor), bubbles.insetNortheast(), southeast$3(), 'northeast', boundsRestriction(anchor, {
  15782. left: 1,
  15783. top: 2
  15784. }), labelPrefix);
  15785. const north = (anchor, element, bubbles) => nu$6(middleX(anchor, element), northY(anchor), bubbles.insetNorth(), south$3(), 'north', boundsRestriction(anchor, { top: 2 }), labelPrefix);
  15786. const south = (anchor, element, bubbles) => nu$6(middleX(anchor, element), southY(anchor, element), bubbles.insetSouth(), north$3(), 'south', boundsRestriction(anchor, { bottom: 3 }), labelPrefix);
  15787. const east = (anchor, element, bubbles) => nu$6(eastEdgeX(anchor, element), centreY(anchor, element), bubbles.insetEast(), west$3(), 'east', boundsRestriction(anchor, { right: 0 }), labelPrefix);
  15788. const west = (anchor, element, bubbles) => nu$6(westEdgeX(anchor), centreY(anchor, element), bubbles.insetWest(), east$3(), 'west', boundsRestriction(anchor, { left: 1 }), labelPrefix);
  15789. const lookupPreserveLayout = lastPlacement => {
  15790. switch (lastPlacement) {
  15791. case 'north':
  15792. return north;
  15793. case 'northeast':
  15794. return northeast;
  15795. case 'northwest':
  15796. return northwest;
  15797. case 'south':
  15798. return south;
  15799. case 'southeast':
  15800. return southeast;
  15801. case 'southwest':
  15802. return southwest;
  15803. case 'east':
  15804. return east;
  15805. case 'west':
  15806. return west;
  15807. }
  15808. };
  15809. const preserve = (anchor, element, bubbles, placee, bounds) => {
  15810. const layout = getPlacement(placee).map(lookupPreserveLayout).getOr(north);
  15811. return layout(anchor, element, bubbles, placee, bounds);
  15812. };
  15813. const lookupFlippedLayout = lastPlacement => {
  15814. switch (lastPlacement) {
  15815. case 'north':
  15816. return south;
  15817. case 'northeast':
  15818. return southeast;
  15819. case 'northwest':
  15820. return southwest;
  15821. case 'south':
  15822. return north;
  15823. case 'southeast':
  15824. return northeast;
  15825. case 'southwest':
  15826. return northwest;
  15827. case 'east':
  15828. return west;
  15829. case 'west':
  15830. return east;
  15831. }
  15832. };
  15833. const flip = (anchor, element, bubbles, placee, bounds) => {
  15834. const layout = getPlacement(placee).map(lookupFlippedLayout).getOr(north);
  15835. return layout(anchor, element, bubbles, placee, bounds);
  15836. };
  15837. const bubbleAlignments$2 = {
  15838. valignCentre: [],
  15839. alignCentre: [],
  15840. alignLeft: [],
  15841. alignRight: [],
  15842. right: [],
  15843. left: [],
  15844. bottom: [],
  15845. top: []
  15846. };
  15847. const getInlineDialogAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
  15848. const bubbleSize = 12;
  15849. const overrides = { maxHeightFunction: expandable$1() };
  15850. const editableAreaAnchor = () => ({
  15851. type: 'node',
  15852. root: getContentContainer(contentAreaElement()),
  15853. node: Optional.from(contentAreaElement()),
  15854. bubble: nu$5(bubbleSize, bubbleSize, bubbleAlignments$2),
  15855. layouts: {
  15856. onRtl: () => [northeast],
  15857. onLtr: () => [northwest]
  15858. },
  15859. overrides
  15860. });
  15861. const standardAnchor = () => ({
  15862. type: 'hotspot',
  15863. hotspot: lazyAnchorbar(),
  15864. bubble: nu$5(-bubbleSize, bubbleSize, bubbleAlignments$2),
  15865. layouts: {
  15866. onRtl: () => [southeast$2],
  15867. onLtr: () => [southwest$2]
  15868. },
  15869. overrides
  15870. });
  15871. return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  15872. };
  15873. const getBannerAnchor = (contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor) => {
  15874. const editableAreaAnchor = () => ({
  15875. type: 'node',
  15876. root: getContentContainer(contentAreaElement()),
  15877. node: Optional.from(contentAreaElement()),
  15878. layouts: {
  15879. onRtl: () => [north],
  15880. onLtr: () => [north]
  15881. }
  15882. });
  15883. const standardAnchor = () => ({
  15884. type: 'hotspot',
  15885. hotspot: lazyAnchorbar(),
  15886. layouts: {
  15887. onRtl: () => [south$2],
  15888. onLtr: () => [south$2]
  15889. }
  15890. });
  15891. return () => lazyUseEditableAreaAnchor() ? editableAreaAnchor() : standardAnchor();
  15892. };
  15893. const getCursorAnchor = (editor, bodyElement) => () => ({
  15894. type: 'selection',
  15895. root: bodyElement(),
  15896. getSelection: () => {
  15897. const rng = editor.selection.getRng();
  15898. return Optional.some(SimSelection.range(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
  15899. }
  15900. });
  15901. const getNodeAnchor$1 = bodyElement => element => ({
  15902. type: 'node',
  15903. root: bodyElement(),
  15904. node: element
  15905. });
  15906. const getAnchors = (editor, lazyAnchorbar, isToolbarTop) => {
  15907. const useFixedToolbarContainer = useFixedContainer(editor);
  15908. const bodyElement = () => SugarElement.fromDom(editor.getBody());
  15909. const contentAreaElement = () => SugarElement.fromDom(editor.getContentAreaContainer());
  15910. const lazyUseEditableAreaAnchor = () => useFixedToolbarContainer || !isToolbarTop();
  15911. return {
  15912. inlineDialog: getInlineDialogAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
  15913. banner: getBannerAnchor(contentAreaElement, lazyAnchorbar, lazyUseEditableAreaAnchor),
  15914. cursor: getCursorAnchor(editor, bodyElement),
  15915. node: getNodeAnchor$1(bodyElement)
  15916. };
  15917. };
  15918. const colorPicker = editor => (callback, value) => {
  15919. const dialog = colorPickerDialog(editor);
  15920. dialog(callback, value);
  15921. };
  15922. const hasCustomColors = editor => () => hasCustomColors$1(editor);
  15923. const getColors = editor => () => getColors$2(editor);
  15924. const getColorCols = editor => () => getColorCols$1(editor);
  15925. const ColorInputBackstage = editor => ({
  15926. colorPicker: colorPicker(editor),
  15927. hasCustomColors: hasCustomColors(editor),
  15928. getColors: getColors(editor),
  15929. getColorCols: getColorCols(editor)
  15930. });
  15931. const isDraggableModal = editor => () => isDraggableModal$1(editor);
  15932. const DialogBackstage = editor => ({ isDraggableModal: isDraggableModal(editor) });
  15933. const HeaderBackstage = editor => {
  15934. const mode = Cell(isToolbarLocationBottom(editor) ? 'bottom' : 'top');
  15935. return {
  15936. isPositionedAtTop: () => mode.get() === 'top',
  15937. getDockingMode: mode.get,
  15938. setDockingMode: mode.set
  15939. };
  15940. };
  15941. const defaultStyleFormats = [
  15942. {
  15943. title: 'Headings',
  15944. items: [
  15945. {
  15946. title: 'Heading 1',
  15947. format: 'h1'
  15948. },
  15949. {
  15950. title: 'Heading 2',
  15951. format: 'h2'
  15952. },
  15953. {
  15954. title: 'Heading 3',
  15955. format: 'h3'
  15956. },
  15957. {
  15958. title: 'Heading 4',
  15959. format: 'h4'
  15960. },
  15961. {
  15962. title: 'Heading 5',
  15963. format: 'h5'
  15964. },
  15965. {
  15966. title: 'Heading 6',
  15967. format: 'h6'
  15968. }
  15969. ]
  15970. },
  15971. {
  15972. title: 'Inline',
  15973. items: [
  15974. {
  15975. title: 'Bold',
  15976. format: 'bold'
  15977. },
  15978. {
  15979. title: 'Italic',
  15980. format: 'italic'
  15981. },
  15982. {
  15983. title: 'Underline',
  15984. format: 'underline'
  15985. },
  15986. {
  15987. title: 'Strikethrough',
  15988. format: 'strikethrough'
  15989. },
  15990. {
  15991. title: 'Superscript',
  15992. format: 'superscript'
  15993. },
  15994. {
  15995. title: 'Subscript',
  15996. format: 'subscript'
  15997. },
  15998. {
  15999. title: 'Code',
  16000. format: 'code'
  16001. }
  16002. ]
  16003. },
  16004. {
  16005. title: 'Blocks',
  16006. items: [
  16007. {
  16008. title: 'Paragraph',
  16009. format: 'p'
  16010. },
  16011. {
  16012. title: 'Blockquote',
  16013. format: 'blockquote'
  16014. },
  16015. {
  16016. title: 'Div',
  16017. format: 'div'
  16018. },
  16019. {
  16020. title: 'Pre',
  16021. format: 'pre'
  16022. }
  16023. ]
  16024. },
  16025. {
  16026. title: 'Align',
  16027. items: [
  16028. {
  16029. title: 'Left',
  16030. format: 'alignleft'
  16031. },
  16032. {
  16033. title: 'Center',
  16034. format: 'aligncenter'
  16035. },
  16036. {
  16037. title: 'Right',
  16038. format: 'alignright'
  16039. },
  16040. {
  16041. title: 'Justify',
  16042. format: 'alignjustify'
  16043. }
  16044. ]
  16045. }
  16046. ];
  16047. const isNestedFormat = format => has$2(format, 'items');
  16048. const isBlockFormat = format => has$2(format, 'block');
  16049. const isInlineFormat = format => has$2(format, 'inline');
  16050. const isSelectorFormat = format => has$2(format, 'selector');
  16051. const mapFormats = userFormats => foldl(userFormats, (acc, fmt) => {
  16052. if (isNestedFormat(fmt)) {
  16053. const result = mapFormats(fmt.items);
  16054. return {
  16055. customFormats: acc.customFormats.concat(result.customFormats),
  16056. formats: acc.formats.concat([{
  16057. title: fmt.title,
  16058. items: result.formats
  16059. }])
  16060. };
  16061. } else if (isInlineFormat(fmt) || isBlockFormat(fmt) || isSelectorFormat(fmt)) {
  16062. const formatName = isString(fmt.name) ? fmt.name : fmt.title.toLowerCase();
  16063. const formatNameWithPrefix = `custom-${ formatName }`;
  16064. return {
  16065. customFormats: acc.customFormats.concat([{
  16066. name: formatNameWithPrefix,
  16067. format: fmt
  16068. }]),
  16069. formats: acc.formats.concat([{
  16070. title: fmt.title,
  16071. format: formatNameWithPrefix,
  16072. icon: fmt.icon
  16073. }])
  16074. };
  16075. } else {
  16076. return {
  16077. ...acc,
  16078. formats: acc.formats.concat(fmt)
  16079. };
  16080. }
  16081. }, {
  16082. customFormats: [],
  16083. formats: []
  16084. });
  16085. const registerCustomFormats = (editor, userFormats) => {
  16086. const result = mapFormats(userFormats);
  16087. const registerFormats = customFormats => {
  16088. each$1(customFormats, fmt => {
  16089. if (!editor.formatter.has(fmt.name)) {
  16090. editor.formatter.register(fmt.name, fmt.format);
  16091. }
  16092. });
  16093. };
  16094. if (editor.formatter) {
  16095. registerFormats(result.customFormats);
  16096. } else {
  16097. editor.on('init', () => {
  16098. registerFormats(result.customFormats);
  16099. });
  16100. }
  16101. return result.formats;
  16102. };
  16103. const getStyleFormats = editor => getUserStyleFormats(editor).map(userFormats => {
  16104. const registeredUserFormats = registerCustomFormats(editor, userFormats);
  16105. return shouldMergeStyleFormats(editor) ? defaultStyleFormats.concat(registeredUserFormats) : registeredUserFormats;
  16106. }).getOr(defaultStyleFormats);
  16107. const processBasic = (item, isSelectedFor, getPreviewFor) => {
  16108. const formatterSpec = {
  16109. type: 'formatter',
  16110. isSelected: isSelectedFor(item.format),
  16111. getStylePreview: getPreviewFor(item.format)
  16112. };
  16113. return deepMerge(item, formatterSpec);
  16114. };
  16115. const register$a = (editor, formats, isSelectedFor, getPreviewFor) => {
  16116. const enrichSupported = item => processBasic(item, isSelectedFor, getPreviewFor);
  16117. const enrichMenu = item => {
  16118. const submenuSpec = { type: 'submenu' };
  16119. return deepMerge(item, submenuSpec);
  16120. };
  16121. const enrichCustom = item => {
  16122. const formatName = isString(item.name) ? item.name : generate$6(item.title);
  16123. const formatNameWithPrefix = `custom-${ formatName }`;
  16124. const customSpec = {
  16125. type: 'formatter',
  16126. format: formatNameWithPrefix,
  16127. isSelected: isSelectedFor(formatNameWithPrefix),
  16128. getStylePreview: getPreviewFor(formatNameWithPrefix)
  16129. };
  16130. const newItem = deepMerge(item, customSpec);
  16131. editor.formatter.register(formatName, newItem);
  16132. return newItem;
  16133. };
  16134. const doEnrich = items => map$2(items, item => {
  16135. const keys$1 = keys(item);
  16136. if (hasNonNullableKey(item, 'items')) {
  16137. const newItems = doEnrich(item.items);
  16138. return deepMerge(enrichMenu(item), { getStyleItems: constant$1(newItems) });
  16139. } else if (hasNonNullableKey(item, 'format')) {
  16140. return enrichSupported(item);
  16141. } else if (keys$1.length === 1 && contains$2(keys$1, 'title')) {
  16142. return deepMerge(item, { type: 'separator' });
  16143. } else {
  16144. return enrichCustom(item);
  16145. }
  16146. });
  16147. return doEnrich(formats);
  16148. };
  16149. const init$8 = editor => {
  16150. const isSelectedFor = format => () => editor.formatter.match(format);
  16151. const getPreviewFor = format => () => {
  16152. const fmt = editor.formatter.get(format);
  16153. return fmt !== undefined ? Optional.some({
  16154. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  16155. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  16156. }) : Optional.none();
  16157. };
  16158. const flatten = fmt => {
  16159. const subs = fmt.items;
  16160. return subs !== undefined && subs.length > 0 ? bind$3(subs, flatten) : [fmt.format];
  16161. };
  16162. const settingsFormats = Cell([]);
  16163. const settingsFlattenedFormats = Cell([]);
  16164. const eventsFormats = Cell([]);
  16165. const eventsFlattenedFormats = Cell([]);
  16166. const replaceSettings = Cell(false);
  16167. editor.on('PreInit', _e => {
  16168. const formats = getStyleFormats(editor);
  16169. const enriched = register$a(editor, formats, isSelectedFor, getPreviewFor);
  16170. settingsFormats.set(enriched);
  16171. settingsFlattenedFormats.set(bind$3(enriched, flatten));
  16172. });
  16173. editor.on('addStyleModifications', e => {
  16174. const modifications = register$a(editor, e.items, isSelectedFor, getPreviewFor);
  16175. eventsFormats.set(modifications);
  16176. replaceSettings.set(e.replace);
  16177. eventsFlattenedFormats.set(bind$3(modifications, flatten));
  16178. });
  16179. const getData = () => {
  16180. const fromSettings = replaceSettings.get() ? [] : settingsFormats.get();
  16181. const fromEvents = eventsFormats.get();
  16182. return fromSettings.concat(fromEvents);
  16183. };
  16184. const getFlattenedKeys = () => {
  16185. const fromSettings = replaceSettings.get() ? [] : settingsFlattenedFormats.get();
  16186. const fromEvents = eventsFlattenedFormats.get();
  16187. return fromSettings.concat(fromEvents);
  16188. };
  16189. return {
  16190. getData,
  16191. getFlattenedKeys
  16192. };
  16193. };
  16194. const isElement = node => isNonNullable(node) && node.nodeType === 1;
  16195. const trim = global$1.trim;
  16196. const hasContentEditableState = value => {
  16197. return node => {
  16198. if (isElement(node)) {
  16199. if (node.contentEditable === value) {
  16200. return true;
  16201. }
  16202. if (node.getAttribute('data-mce-contenteditable') === value) {
  16203. return true;
  16204. }
  16205. }
  16206. return false;
  16207. };
  16208. };
  16209. const isContentEditableTrue = hasContentEditableState('true');
  16210. const isContentEditableFalse = hasContentEditableState('false');
  16211. const create = (type, title, url, level, attach) => {
  16212. return {
  16213. type,
  16214. title,
  16215. url,
  16216. level,
  16217. attach
  16218. };
  16219. };
  16220. const isChildOfContentEditableTrue = node => {
  16221. while (node = node.parentNode) {
  16222. const value = node.contentEditable;
  16223. if (value && value !== 'inherit') {
  16224. return isContentEditableTrue(node);
  16225. }
  16226. }
  16227. return false;
  16228. };
  16229. const select = (selector, root) => {
  16230. return map$2(descendants(SugarElement.fromDom(root), selector), element => {
  16231. return element.dom;
  16232. });
  16233. };
  16234. const getElementText = elm => {
  16235. return elm.innerText || elm.textContent;
  16236. };
  16237. const getOrGenerateId = elm => {
  16238. return elm.id ? elm.id : generate$6('h');
  16239. };
  16240. const isAnchor = elm => {
  16241. return elm && elm.nodeName === 'A' && (elm.id || elm.name) !== undefined;
  16242. };
  16243. const isValidAnchor = elm => {
  16244. return isAnchor(elm) && isEditable(elm);
  16245. };
  16246. const isHeader = elm => {
  16247. return elm && /^(H[1-6])$/.test(elm.nodeName);
  16248. };
  16249. const isEditable = elm => {
  16250. return isChildOfContentEditableTrue(elm) && !isContentEditableFalse(elm);
  16251. };
  16252. const isValidHeader = elm => {
  16253. return isHeader(elm) && isEditable(elm);
  16254. };
  16255. const getLevel = elm => {
  16256. return isHeader(elm) ? parseInt(elm.nodeName.substr(1), 10) : 0;
  16257. };
  16258. const headerTarget = elm => {
  16259. const headerId = getOrGenerateId(elm);
  16260. const attach = () => {
  16261. elm.id = headerId;
  16262. };
  16263. return create('header', getElementText(elm), '#' + headerId, getLevel(elm), attach);
  16264. };
  16265. const anchorTarget = elm => {
  16266. const anchorId = elm.id || elm.name;
  16267. const anchorText = getElementText(elm);
  16268. return create('anchor', anchorText ? anchorText : '#' + anchorId, '#' + anchorId, 0, noop);
  16269. };
  16270. const getHeaderTargets = elms => {
  16271. return map$2(filter$2(elms, isValidHeader), headerTarget);
  16272. };
  16273. const getAnchorTargets = elms => {
  16274. return map$2(filter$2(elms, isValidAnchor), anchorTarget);
  16275. };
  16276. const getTargetElements = elm => {
  16277. const elms = select('h1,h2,h3,h4,h5,h6,a:not([href])', elm);
  16278. return elms;
  16279. };
  16280. const hasTitle = target => {
  16281. return trim(target.title).length > 0;
  16282. };
  16283. const find = elm => {
  16284. const elms = getTargetElements(elm);
  16285. return filter$2(getHeaderTargets(elms).concat(getAnchorTargets(elms)), hasTitle);
  16286. };
  16287. const LinkTargets = { find };
  16288. const STORAGE_KEY = 'tinymce-url-history';
  16289. const HISTORY_LENGTH = 5;
  16290. const isHttpUrl = url => isString(url) && /^https?/.test(url);
  16291. const isArrayOfUrl = a => isArray(a) && a.length <= HISTORY_LENGTH && forall(a, isHttpUrl);
  16292. const isRecordOfUrlArray = r => isObject(r) && find$4(r, value => !isArrayOfUrl(value)).isNone();
  16293. const getAllHistory = () => {
  16294. const unparsedHistory = global$4.getItem(STORAGE_KEY);
  16295. if (unparsedHistory === null) {
  16296. return {};
  16297. }
  16298. let history;
  16299. try {
  16300. history = JSON.parse(unparsedHistory);
  16301. } catch (e) {
  16302. if (e instanceof SyntaxError) {
  16303. console.log('Local storage ' + STORAGE_KEY + ' was not valid JSON', e);
  16304. return {};
  16305. }
  16306. throw e;
  16307. }
  16308. if (!isRecordOfUrlArray(history)) {
  16309. console.log('Local storage ' + STORAGE_KEY + ' was not valid format', history);
  16310. return {};
  16311. }
  16312. return history;
  16313. };
  16314. const setAllHistory = history => {
  16315. if (!isRecordOfUrlArray(history)) {
  16316. throw new Error('Bad format for history:\n' + JSON.stringify(history));
  16317. }
  16318. global$4.setItem(STORAGE_KEY, JSON.stringify(history));
  16319. };
  16320. const getHistory = fileType => {
  16321. const history = getAllHistory();
  16322. return get$g(history, fileType).getOr([]);
  16323. };
  16324. const addToHistory = (url, fileType) => {
  16325. if (!isHttpUrl(url)) {
  16326. return;
  16327. }
  16328. const history = getAllHistory();
  16329. const items = get$g(history, fileType).getOr([]);
  16330. const itemsWithoutUrl = filter$2(items, item => item !== url);
  16331. history[fileType] = [url].concat(itemsWithoutUrl).slice(0, HISTORY_LENGTH);
  16332. setAllHistory(history);
  16333. };
  16334. const isTruthy = value => !!value;
  16335. const makeMap = value => map$1(global$1.makeMap(value, /[, ]/), isTruthy);
  16336. const getPicker = editor => Optional.from(getFilePickerCallback(editor));
  16337. const getPickerTypes = editor => {
  16338. const optFileTypes = Optional.from(getFilePickerTypes(editor)).filter(isTruthy).map(makeMap);
  16339. return getPicker(editor).fold(never, _picker => optFileTypes.fold(always, types => keys(types).length > 0 ? types : false));
  16340. };
  16341. const getPickerSetting = (editor, filetype) => {
  16342. const pickerTypes = getPickerTypes(editor);
  16343. if (isBoolean(pickerTypes)) {
  16344. return pickerTypes ? getPicker(editor) : Optional.none();
  16345. } else {
  16346. return pickerTypes[filetype] ? getPicker(editor) : Optional.none();
  16347. }
  16348. };
  16349. const getUrlPicker = (editor, filetype) => getPickerSetting(editor, filetype).map(picker => entry => Future.nu(completer => {
  16350. const handler = (value, meta) => {
  16351. if (!isString(value)) {
  16352. throw new Error('Expected value to be string');
  16353. }
  16354. if (meta !== undefined && !isObject(meta)) {
  16355. throw new Error('Expected meta to be a object');
  16356. }
  16357. const r = {
  16358. value,
  16359. meta
  16360. };
  16361. completer(r);
  16362. };
  16363. const meta = {
  16364. filetype,
  16365. fieldname: entry.fieldname,
  16366. ...Optional.from(entry.meta).getOr({})
  16367. };
  16368. picker.call(editor, handler, entry.value, meta);
  16369. }));
  16370. const getTextSetting = value => Optional.from(value).filter(isString).getOrUndefined();
  16371. const getLinkInformation = editor => {
  16372. if (!useTypeaheadUrls(editor)) {
  16373. return Optional.none();
  16374. }
  16375. return Optional.some({
  16376. targets: LinkTargets.find(editor.getBody()),
  16377. anchorTop: getTextSetting(getAnchorTop(editor)),
  16378. anchorBottom: getTextSetting(getAnchorBottom(editor))
  16379. });
  16380. };
  16381. const getValidationHandler = editor => Optional.from(getFilePickerValidatorHandler(editor));
  16382. const UrlInputBackstage = editor => ({
  16383. getHistory,
  16384. addToHistory,
  16385. getLinkInformation: () => getLinkInformation(editor),
  16386. getValidationHandler: () => getValidationHandler(editor),
  16387. getUrlPicker: filetype => getUrlPicker(editor, filetype)
  16388. });
  16389. const init$7 = (lazySink, editor, lazyAnchorbar) => {
  16390. const contextMenuState = Cell(false);
  16391. const toolbar = HeaderBackstage(editor);
  16392. const backstage = {
  16393. shared: {
  16394. providers: {
  16395. icons: () => editor.ui.registry.getAll().icons,
  16396. menuItems: () => editor.ui.registry.getAll().menuItems,
  16397. translate: global$8.translate,
  16398. isDisabled: () => editor.mode.isReadOnly() || !editor.ui.isEnabled(),
  16399. getOption: editor.options.get
  16400. },
  16401. interpreter: s => interpretWithoutForm(s, {}, backstage),
  16402. anchors: getAnchors(editor, lazyAnchorbar, toolbar.isPositionedAtTop),
  16403. header: toolbar,
  16404. getSink: lazySink
  16405. },
  16406. urlinput: UrlInputBackstage(editor),
  16407. styles: init$8(editor),
  16408. colorinput: ColorInputBackstage(editor),
  16409. dialog: DialogBackstage(editor),
  16410. isContextMenuOpen: () => contextMenuState.get(),
  16411. setContextMenuState: state => contextMenuState.set(state)
  16412. };
  16413. return backstage;
  16414. };
  16415. const setup$b = (editor, mothership, uiMothership) => {
  16416. const broadcastEvent = (name, evt) => {
  16417. each$1([
  16418. mothership,
  16419. uiMothership
  16420. ], ship => {
  16421. ship.broadcastEvent(name, evt);
  16422. });
  16423. };
  16424. const broadcastOn = (channel, message) => {
  16425. each$1([
  16426. mothership,
  16427. uiMothership
  16428. ], ship => {
  16429. ship.broadcastOn([channel], message);
  16430. });
  16431. };
  16432. const fireDismissPopups = evt => broadcastOn(dismissPopups(), { target: evt.target });
  16433. const doc = getDocument();
  16434. const onTouchstart = bind(doc, 'touchstart', fireDismissPopups);
  16435. const onTouchmove = bind(doc, 'touchmove', evt => broadcastEvent(documentTouchmove(), evt));
  16436. const onTouchend = bind(doc, 'touchend', evt => broadcastEvent(documentTouchend(), evt));
  16437. const onMousedown = bind(doc, 'mousedown', fireDismissPopups);
  16438. const onMouseup = bind(doc, 'mouseup', evt => {
  16439. if (evt.raw.button === 0) {
  16440. broadcastOn(mouseReleased(), { target: evt.target });
  16441. }
  16442. });
  16443. const onContentClick = raw => broadcastOn(dismissPopups(), { target: SugarElement.fromDom(raw.target) });
  16444. const onContentMouseup = raw => {
  16445. if (raw.button === 0) {
  16446. broadcastOn(mouseReleased(), { target: SugarElement.fromDom(raw.target) });
  16447. }
  16448. };
  16449. const onContentMousedown = () => {
  16450. each$1(editor.editorManager.get(), loopEditor => {
  16451. if (editor !== loopEditor) {
  16452. loopEditor.dispatch('DismissPopups', { relatedTarget: editor });
  16453. }
  16454. });
  16455. };
  16456. const onWindowScroll = evt => broadcastEvent(windowScroll(), fromRawEvent(evt));
  16457. const onWindowResize = evt => {
  16458. broadcastOn(repositionPopups(), {});
  16459. broadcastEvent(windowResize(), fromRawEvent(evt));
  16460. };
  16461. const onEditorResize = () => broadcastOn(repositionPopups(), {});
  16462. const onEditorProgress = evt => {
  16463. if (evt.state) {
  16464. broadcastOn(dismissPopups(), { target: SugarElement.fromDom(editor.getContainer()) });
  16465. }
  16466. };
  16467. const onDismissPopups = event => {
  16468. broadcastOn(dismissPopups(), { target: SugarElement.fromDom(event.relatedTarget.getContainer()) });
  16469. };
  16470. editor.on('PostRender', () => {
  16471. editor.on('click', onContentClick);
  16472. editor.on('tap', onContentClick);
  16473. editor.on('mouseup', onContentMouseup);
  16474. editor.on('mousedown', onContentMousedown);
  16475. editor.on('ScrollWindow', onWindowScroll);
  16476. editor.on('ResizeWindow', onWindowResize);
  16477. editor.on('ResizeEditor', onEditorResize);
  16478. editor.on('AfterProgressState', onEditorProgress);
  16479. editor.on('DismissPopups', onDismissPopups);
  16480. });
  16481. editor.on('remove', () => {
  16482. editor.off('click', onContentClick);
  16483. editor.off('tap', onContentClick);
  16484. editor.off('mouseup', onContentMouseup);
  16485. editor.off('mousedown', onContentMousedown);
  16486. editor.off('ScrollWindow', onWindowScroll);
  16487. editor.off('ResizeWindow', onWindowResize);
  16488. editor.off('ResizeEditor', onEditorResize);
  16489. editor.off('AfterProgressState', onEditorProgress);
  16490. editor.off('DismissPopups', onDismissPopups);
  16491. onMousedown.unbind();
  16492. onTouchstart.unbind();
  16493. onTouchmove.unbind();
  16494. onTouchend.unbind();
  16495. onMouseup.unbind();
  16496. });
  16497. editor.on('detach', () => {
  16498. detachSystem(mothership);
  16499. detachSystem(uiMothership);
  16500. mothership.destroy();
  16501. uiMothership.destroy();
  16502. });
  16503. };
  16504. const parts$a = AlloyParts;
  16505. const partType = PartType;
  16506. const schema$f = constant$1([
  16507. defaulted('shell', false),
  16508. required$1('makeItem'),
  16509. defaulted('setupItem', noop),
  16510. SketchBehaviours.field('listBehaviours', [Replacing])
  16511. ]);
  16512. const customListDetail = () => ({ behaviours: derive$1([Replacing.config({})]) });
  16513. const itemsPart = optional({
  16514. name: 'items',
  16515. overrides: customListDetail
  16516. });
  16517. const parts$9 = constant$1([itemsPart]);
  16518. const name = constant$1('CustomList');
  16519. const factory$d = (detail, components, _spec, _external) => {
  16520. const setItems = (list, items) => {
  16521. getListContainer(list).fold(() => {
  16522. console.error('Custom List was defined to not be a shell, but no item container was specified in components');
  16523. throw new Error('Custom List was defined to not be a shell, but no item container was specified in components');
  16524. }, container => {
  16525. const itemComps = Replacing.contents(container);
  16526. const numListsRequired = items.length;
  16527. const numListsToAdd = numListsRequired - itemComps.length;
  16528. const itemsToAdd = numListsToAdd > 0 ? range$2(numListsToAdd, () => detail.makeItem()) : [];
  16529. const itemsToRemove = itemComps.slice(numListsRequired);
  16530. each$1(itemsToRemove, item => Replacing.remove(container, item));
  16531. each$1(itemsToAdd, item => Replacing.append(container, item));
  16532. const builtLists = Replacing.contents(container);
  16533. each$1(builtLists, (item, i) => {
  16534. detail.setupItem(list, item, items[i], i);
  16535. });
  16536. });
  16537. };
  16538. const extra = detail.shell ? {
  16539. behaviours: [Replacing.config({})],
  16540. components: []
  16541. } : {
  16542. behaviours: [],
  16543. components
  16544. };
  16545. const getListContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'items');
  16546. return {
  16547. uid: detail.uid,
  16548. dom: detail.dom,
  16549. components: extra.components,
  16550. behaviours: augment(detail.listBehaviours, extra.behaviours),
  16551. apis: { setItems }
  16552. };
  16553. };
  16554. const CustomList = composite({
  16555. name: name(),
  16556. configFields: schema$f(),
  16557. partFields: parts$9(),
  16558. factory: factory$d,
  16559. apis: {
  16560. setItems: (apis, list, items) => {
  16561. apis.setItems(list, items);
  16562. }
  16563. }
  16564. });
  16565. const schema$e = constant$1([
  16566. required$1('dom'),
  16567. defaulted('shell', true),
  16568. field('toolbarBehaviours', [Replacing])
  16569. ]);
  16570. const enhanceGroups = () => ({ behaviours: derive$1([Replacing.config({})]) });
  16571. const parts$8 = constant$1([optional({
  16572. name: 'groups',
  16573. overrides: enhanceGroups
  16574. })]);
  16575. const factory$c = (detail, components, _spec, _externals) => {
  16576. const setGroups = (toolbar, groups) => {
  16577. getGroupContainer(toolbar).fold(() => {
  16578. console.error('Toolbar was defined to not be a shell, but no groups container was specified in components');
  16579. throw new Error('Toolbar was defined to not be a shell, but no groups container was specified in components');
  16580. }, container => {
  16581. Replacing.set(container, groups);
  16582. });
  16583. };
  16584. const getGroupContainer = component => detail.shell ? Optional.some(component) : getPart(component, detail, 'groups');
  16585. const extra = detail.shell ? {
  16586. behaviours: [Replacing.config({})],
  16587. components: []
  16588. } : {
  16589. behaviours: [],
  16590. components
  16591. };
  16592. return {
  16593. uid: detail.uid,
  16594. dom: detail.dom,
  16595. components: extra.components,
  16596. behaviours: augment(detail.toolbarBehaviours, extra.behaviours),
  16597. apis: { setGroups },
  16598. domModification: { attributes: { role: 'group' } }
  16599. };
  16600. };
  16601. const Toolbar = composite({
  16602. name: 'Toolbar',
  16603. configFields: schema$e(),
  16604. partFields: parts$8(),
  16605. factory: factory$c,
  16606. apis: {
  16607. setGroups: (apis, toolbar, groups) => {
  16608. apis.setGroups(toolbar, groups);
  16609. }
  16610. }
  16611. });
  16612. const setup$a = noop;
  16613. const isDocked$2 = never;
  16614. const getBehaviours$1 = constant$1([]);
  16615. var StaticHeader = /*#__PURE__*/Object.freeze({
  16616. __proto__: null,
  16617. setup: setup$a,
  16618. isDocked: isDocked$2,
  16619. getBehaviours: getBehaviours$1
  16620. });
  16621. const getOffsetParent = element => {
  16622. const isFixed = is$1(getRaw(element, 'position'), 'fixed');
  16623. const offsetParent$1 = isFixed ? Optional.none() : offsetParent(element);
  16624. return offsetParent$1.orThunk(() => {
  16625. const marker = SugarElement.fromTag('span');
  16626. return parent(element).bind(parent => {
  16627. append$2(parent, marker);
  16628. const offsetParent$1 = offsetParent(marker);
  16629. remove$5(marker);
  16630. return offsetParent$1;
  16631. });
  16632. });
  16633. };
  16634. const getOrigin = element => getOffsetParent(element).map(absolute$3).getOrThunk(() => SugarPosition(0, 0));
  16635. const morphAdt = Adt.generate([
  16636. { static: [] },
  16637. { absolute: ['positionCss'] },
  16638. { fixed: ['positionCss'] }
  16639. ]);
  16640. const appear = (component, contextualInfo) => {
  16641. const elem = component.element;
  16642. add$2(elem, contextualInfo.transitionClass);
  16643. remove$2(elem, contextualInfo.fadeOutClass);
  16644. add$2(elem, contextualInfo.fadeInClass);
  16645. contextualInfo.onShow(component);
  16646. };
  16647. const disappear = (component, contextualInfo) => {
  16648. const elem = component.element;
  16649. add$2(elem, contextualInfo.transitionClass);
  16650. remove$2(elem, contextualInfo.fadeInClass);
  16651. add$2(elem, contextualInfo.fadeOutClass);
  16652. contextualInfo.onHide(component);
  16653. };
  16654. const isPartiallyVisible = (box, viewport) => box.y < viewport.bottom && box.bottom > viewport.y;
  16655. const isTopCompletelyVisible = (box, viewport) => box.y >= viewport.y;
  16656. const isBottomCompletelyVisible = (box, viewport) => box.bottom <= viewport.bottom;
  16657. const isVisibleForModes = (modes, box, viewport) => forall(modes, mode => {
  16658. switch (mode) {
  16659. case 'bottom':
  16660. return isBottomCompletelyVisible(box, viewport);
  16661. case 'top':
  16662. return isTopCompletelyVisible(box, viewport);
  16663. }
  16664. });
  16665. const getPrior = (elem, state) => state.getInitialPos().map(pos => bounds(pos.bounds.x, pos.bounds.y, get$c(elem), get$d(elem)));
  16666. const storePrior = (elem, box, state) => {
  16667. state.setInitialPos({
  16668. style: getAllRaw(elem),
  16669. position: get$e(elem, 'position') || 'static',
  16670. bounds: box
  16671. });
  16672. };
  16673. const revertToOriginal = (elem, box, state) => state.getInitialPos().bind(position => {
  16674. state.clearInitialPos();
  16675. switch (position.position) {
  16676. case 'static':
  16677. return Optional.some(morphAdt.static());
  16678. case 'absolute':
  16679. const offsetBox = getOffsetParent(elem).map(box$1).getOrThunk(() => box$1(body()));
  16680. return Optional.some(morphAdt.absolute(NuPositionCss('absolute', get$g(position.style, 'left').map(_left => box.x - offsetBox.x), get$g(position.style, 'top').map(_top => box.y - offsetBox.y), get$g(position.style, 'right').map(_right => offsetBox.right - box.right), get$g(position.style, 'bottom').map(_bottom => offsetBox.bottom - box.bottom))));
  16681. default:
  16682. return Optional.none();
  16683. }
  16684. });
  16685. const morphToOriginal = (elem, viewport, state) => getPrior(elem, state).filter(box => isVisibleForModes(state.getModes(), box, viewport)).bind(box => revertToOriginal(elem, box, state));
  16686. const morphToFixed = (elem, viewport, state) => {
  16687. const box = box$1(elem);
  16688. if (!isVisibleForModes(state.getModes(), box, viewport)) {
  16689. storePrior(elem, box, state);
  16690. const winBox = win();
  16691. const left = box.x - winBox.x;
  16692. const top = viewport.y - winBox.y;
  16693. const bottom = winBox.bottom - viewport.bottom;
  16694. const isTop = box.y <= viewport.y;
  16695. return Optional.some(morphAdt.fixed(NuPositionCss('fixed', Optional.some(left), isTop ? Optional.some(top) : Optional.none(), Optional.none(), !isTop ? Optional.some(bottom) : Optional.none())));
  16696. } else {
  16697. return Optional.none();
  16698. }
  16699. };
  16700. const getMorph = (component, viewport, state) => {
  16701. const elem = component.element;
  16702. const isDocked = is$1(getRaw(elem, 'position'), 'fixed');
  16703. return isDocked ? morphToOriginal(elem, viewport, state) : morphToFixed(elem, viewport, state);
  16704. };
  16705. const getMorphToOriginal = (component, state) => {
  16706. const elem = component.element;
  16707. return getPrior(elem, state).bind(box => revertToOriginal(elem, box, state));
  16708. };
  16709. const morphToStatic = (component, config, state) => {
  16710. state.setDocked(false);
  16711. each$1([
  16712. 'left',
  16713. 'right',
  16714. 'top',
  16715. 'bottom',
  16716. 'position'
  16717. ], prop => remove$6(component.element, prop));
  16718. config.onUndocked(component);
  16719. };
  16720. const morphToCoord = (component, config, state, position) => {
  16721. const isDocked = position.position === 'fixed';
  16722. state.setDocked(isDocked);
  16723. applyPositionCss(component.element, position);
  16724. const method = isDocked ? config.onDocked : config.onUndocked;
  16725. method(component);
  16726. };
  16727. const updateVisibility = (component, config, state, viewport, morphToDocked = false) => {
  16728. config.contextual.each(contextInfo => {
  16729. contextInfo.lazyContext(component).each(box => {
  16730. const isVisible = isPartiallyVisible(box, viewport);
  16731. if (isVisible !== state.isVisible()) {
  16732. state.setVisible(isVisible);
  16733. if (morphToDocked && !isVisible) {
  16734. add$1(component.element, [contextInfo.fadeOutClass]);
  16735. contextInfo.onHide(component);
  16736. } else {
  16737. const method = isVisible ? appear : disappear;
  16738. method(component, contextInfo);
  16739. }
  16740. }
  16741. });
  16742. });
  16743. };
  16744. const refreshInternal = (component, config, state) => {
  16745. const viewport = config.lazyViewport(component);
  16746. const isDocked = state.isDocked();
  16747. if (isDocked) {
  16748. updateVisibility(component, config, state, viewport);
  16749. }
  16750. getMorph(component, viewport, state).each(morph => {
  16751. morph.fold(() => morphToStatic(component, config, state), position => morphToCoord(component, config, state, position), position => {
  16752. updateVisibility(component, config, state, viewport, true);
  16753. morphToCoord(component, config, state, position);
  16754. });
  16755. });
  16756. };
  16757. const resetInternal = (component, config, state) => {
  16758. const elem = component.element;
  16759. state.setDocked(false);
  16760. getMorphToOriginal(component, state).each(morph => {
  16761. morph.fold(() => morphToStatic(component, config, state), position => morphToCoord(component, config, state, position), noop);
  16762. });
  16763. state.setVisible(true);
  16764. config.contextual.each(contextInfo => {
  16765. remove$1(elem, [
  16766. contextInfo.fadeInClass,
  16767. contextInfo.fadeOutClass,
  16768. contextInfo.transitionClass
  16769. ]);
  16770. contextInfo.onShow(component);
  16771. });
  16772. refresh$4(component, config, state);
  16773. };
  16774. const refresh$4 = (component, config, state) => {
  16775. if (component.getSystem().isConnected()) {
  16776. refreshInternal(component, config, state);
  16777. }
  16778. };
  16779. const reset = (component, config, state) => {
  16780. if (state.isDocked()) {
  16781. resetInternal(component, config, state);
  16782. }
  16783. };
  16784. const isDocked$1 = (component, config, state) => state.isDocked();
  16785. const setModes = (component, config, state, modes) => state.setModes(modes);
  16786. const getModes = (component, config, state) => state.getModes();
  16787. var DockingApis = /*#__PURE__*/Object.freeze({
  16788. __proto__: null,
  16789. refresh: refresh$4,
  16790. reset: reset,
  16791. isDocked: isDocked$1,
  16792. getModes: getModes,
  16793. setModes: setModes
  16794. });
  16795. const events$5 = (dockInfo, dockState) => derive$2([
  16796. runOnSource(transitionend(), (component, simulatedEvent) => {
  16797. dockInfo.contextual.each(contextInfo => {
  16798. if (has(component.element, contextInfo.transitionClass)) {
  16799. remove$1(component.element, [
  16800. contextInfo.transitionClass,
  16801. contextInfo.fadeInClass
  16802. ]);
  16803. const notify = dockState.isVisible() ? contextInfo.onShown : contextInfo.onHidden;
  16804. notify(component);
  16805. }
  16806. simulatedEvent.stop();
  16807. });
  16808. }),
  16809. run$1(windowScroll(), (component, _) => {
  16810. refresh$4(component, dockInfo, dockState);
  16811. }),
  16812. run$1(windowResize(), (component, _) => {
  16813. reset(component, dockInfo, dockState);
  16814. })
  16815. ]);
  16816. var ActiveDocking = /*#__PURE__*/Object.freeze({
  16817. __proto__: null,
  16818. events: events$5
  16819. });
  16820. var DockingSchema = [
  16821. optionObjOf('contextual', [
  16822. requiredString('fadeInClass'),
  16823. requiredString('fadeOutClass'),
  16824. requiredString('transitionClass'),
  16825. requiredFunction('lazyContext'),
  16826. onHandler('onShow'),
  16827. onHandler('onShown'),
  16828. onHandler('onHide'),
  16829. onHandler('onHidden')
  16830. ]),
  16831. defaultedFunction('lazyViewport', win),
  16832. defaultedArrayOf('modes', [
  16833. 'top',
  16834. 'bottom'
  16835. ], string),
  16836. onHandler('onDocked'),
  16837. onHandler('onUndocked')
  16838. ];
  16839. const init$6 = spec => {
  16840. const docked = Cell(false);
  16841. const visible = Cell(true);
  16842. const initialBounds = value$2();
  16843. const modes = Cell(spec.modes);
  16844. const readState = () => `docked: ${ docked.get() }, visible: ${ visible.get() }, modes: ${ modes.get().join(',') }`;
  16845. return nu$8({
  16846. isDocked: docked.get,
  16847. setDocked: docked.set,
  16848. getInitialPos: initialBounds.get,
  16849. setInitialPos: initialBounds.set,
  16850. clearInitialPos: initialBounds.clear,
  16851. isVisible: visible.get,
  16852. setVisible: visible.set,
  16853. getModes: modes.get,
  16854. setModes: modes.set,
  16855. readState
  16856. });
  16857. };
  16858. var DockingState = /*#__PURE__*/Object.freeze({
  16859. __proto__: null,
  16860. init: init$6
  16861. });
  16862. const Docking = create$3({
  16863. fields: DockingSchema,
  16864. name: 'docking',
  16865. active: ActiveDocking,
  16866. apis: DockingApis,
  16867. state: DockingState
  16868. });
  16869. const toolbarHeightChange = constant$1(generate$6('toolbar-height-change'));
  16870. const visibility = {
  16871. fadeInClass: 'tox-editor-dock-fadein',
  16872. fadeOutClass: 'tox-editor-dock-fadeout',
  16873. transitionClass: 'tox-editor-dock-transition'
  16874. };
  16875. const editorStickyOnClass = 'tox-tinymce--toolbar-sticky-on';
  16876. const editorStickyOffClass = 'tox-tinymce--toolbar-sticky-off';
  16877. const scrollFromBehindHeader = (e, containerHeader) => {
  16878. const doc = owner$4(containerHeader);
  16879. const viewHeight = doc.dom.defaultView.innerHeight;
  16880. const scrollPos = get$b(doc);
  16881. const markerElement = SugarElement.fromDom(e.elm);
  16882. const markerPos = absolute$2(markerElement);
  16883. const markerHeight = get$d(markerElement);
  16884. const markerTop = markerPos.y;
  16885. const markerBottom = markerTop + markerHeight;
  16886. const editorHeaderPos = absolute$3(containerHeader);
  16887. const editorHeaderHeight = get$d(containerHeader);
  16888. const editorHeaderTop = editorHeaderPos.top;
  16889. const editorHeaderBottom = editorHeaderTop + editorHeaderHeight;
  16890. const editorHeaderDockedAtTop = Math.abs(editorHeaderTop - scrollPos.top) < 2;
  16891. const editorHeaderDockedAtBottom = Math.abs(editorHeaderBottom - (scrollPos.top + viewHeight)) < 2;
  16892. if (editorHeaderDockedAtTop && markerTop < editorHeaderBottom) {
  16893. to(scrollPos.left, markerTop - editorHeaderHeight, doc);
  16894. } else if (editorHeaderDockedAtBottom && markerBottom > editorHeaderTop) {
  16895. const y = markerTop - viewHeight + markerHeight + editorHeaderHeight;
  16896. to(scrollPos.left, y, doc);
  16897. }
  16898. };
  16899. const isDockedMode = (header, mode) => contains$2(Docking.getModes(header), mode);
  16900. const updateIframeContentFlow = header => {
  16901. const getOccupiedHeight = elm => getOuter$2(elm) + (parseInt(get$e(elm, 'margin-top'), 10) || 0) + (parseInt(get$e(elm, 'margin-bottom'), 10) || 0);
  16902. const elm = header.element;
  16903. parent(elm).each(parentElem => {
  16904. const padding = 'padding-' + Docking.getModes(header)[0];
  16905. if (Docking.isDocked(header)) {
  16906. const parentWidth = get$c(parentElem);
  16907. set$8(elm, 'width', parentWidth + 'px');
  16908. set$8(parentElem, padding, getOccupiedHeight(elm) + 'px');
  16909. } else {
  16910. remove$6(elm, 'width');
  16911. remove$6(parentElem, padding);
  16912. }
  16913. });
  16914. };
  16915. const updateSinkVisibility = (sinkElem, visible) => {
  16916. if (visible) {
  16917. remove$2(sinkElem, visibility.fadeOutClass);
  16918. add$1(sinkElem, [
  16919. visibility.transitionClass,
  16920. visibility.fadeInClass
  16921. ]);
  16922. } else {
  16923. remove$2(sinkElem, visibility.fadeInClass);
  16924. add$1(sinkElem, [
  16925. visibility.fadeOutClass,
  16926. visibility.transitionClass
  16927. ]);
  16928. }
  16929. };
  16930. const updateEditorClasses = (editor, docked) => {
  16931. const editorContainer = SugarElement.fromDom(editor.getContainer());
  16932. if (docked) {
  16933. add$2(editorContainer, editorStickyOnClass);
  16934. remove$2(editorContainer, editorStickyOffClass);
  16935. } else {
  16936. add$2(editorContainer, editorStickyOffClass);
  16937. remove$2(editorContainer, editorStickyOnClass);
  16938. }
  16939. };
  16940. const restoreFocus = (headerElem, focusedElem) => {
  16941. const ownerDoc = owner$4(focusedElem);
  16942. active$1(ownerDoc).filter(activeElm => !eq(focusedElem, activeElm)).filter(activeElm => eq(activeElm, SugarElement.fromDom(ownerDoc.dom.body)) || contains(headerElem, activeElm)).each(() => focus$3(focusedElem));
  16943. };
  16944. const findFocusedElem = (rootElm, lazySink) => search(rootElm).orThunk(() => lazySink().toOptional().bind(sink => search(sink.element)));
  16945. const setup$9 = (editor, sharedBackstage, lazyHeader) => {
  16946. if (!editor.inline) {
  16947. if (!sharedBackstage.header.isPositionedAtTop()) {
  16948. editor.on('ResizeEditor', () => {
  16949. lazyHeader().each(Docking.reset);
  16950. });
  16951. }
  16952. editor.on('ResizeWindow ResizeEditor', () => {
  16953. lazyHeader().each(updateIframeContentFlow);
  16954. });
  16955. editor.on('SkinLoaded', () => {
  16956. lazyHeader().each(comp => {
  16957. Docking.isDocked(comp) ? Docking.reset(comp) : Docking.refresh(comp);
  16958. });
  16959. });
  16960. editor.on('FullscreenStateChanged', () => {
  16961. lazyHeader().each(Docking.reset);
  16962. });
  16963. }
  16964. editor.on('AfterScrollIntoView', e => {
  16965. lazyHeader().each(header => {
  16966. Docking.refresh(header);
  16967. const headerElem = header.element;
  16968. if (isVisible(headerElem)) {
  16969. scrollFromBehindHeader(e, headerElem);
  16970. }
  16971. });
  16972. });
  16973. editor.on('PostRender', () => {
  16974. updateEditorClasses(editor, false);
  16975. });
  16976. };
  16977. const isDocked = lazyHeader => lazyHeader().map(Docking.isDocked).getOr(false);
  16978. const getIframeBehaviours = () => [Receiving.config({ channels: { [toolbarHeightChange()]: { onReceive: updateIframeContentFlow } } })];
  16979. const getBehaviours = (editor, sharedBackstage) => {
  16980. const focusedElm = value$2();
  16981. const lazySink = sharedBackstage.getSink;
  16982. const runOnSinkElement = f => {
  16983. lazySink().each(sink => f(sink.element));
  16984. };
  16985. const onDockingSwitch = comp => {
  16986. if (!editor.inline) {
  16987. updateIframeContentFlow(comp);
  16988. }
  16989. updateEditorClasses(editor, Docking.isDocked(comp));
  16990. comp.getSystem().broadcastOn([repositionPopups()], {});
  16991. lazySink().each(sink => sink.getSystem().broadcastOn([repositionPopups()], {}));
  16992. };
  16993. const additionalBehaviours = editor.inline ? [] : getIframeBehaviours();
  16994. return [
  16995. Focusing.config({}),
  16996. Docking.config({
  16997. contextual: {
  16998. lazyContext: comp => {
  16999. const headerHeight = getOuter$2(comp.element);
  17000. const container = editor.inline ? editor.getContentAreaContainer() : editor.getContainer();
  17001. const box = box$1(SugarElement.fromDom(container));
  17002. const boxHeight = box.height - headerHeight;
  17003. const topBound = box.y + (isDockedMode(comp, 'top') ? 0 : headerHeight);
  17004. return Optional.some(bounds(box.x, topBound, box.width, boxHeight));
  17005. },
  17006. onShow: () => {
  17007. runOnSinkElement(elem => updateSinkVisibility(elem, true));
  17008. },
  17009. onShown: comp => {
  17010. runOnSinkElement(elem => remove$1(elem, [
  17011. visibility.transitionClass,
  17012. visibility.fadeInClass
  17013. ]));
  17014. focusedElm.get().each(elem => {
  17015. restoreFocus(comp.element, elem);
  17016. focusedElm.clear();
  17017. });
  17018. },
  17019. onHide: comp => {
  17020. findFocusedElem(comp.element, lazySink).fold(focusedElm.clear, focusedElm.set);
  17021. runOnSinkElement(elem => updateSinkVisibility(elem, false));
  17022. },
  17023. onHidden: () => {
  17024. runOnSinkElement(elem => remove$1(elem, [visibility.transitionClass]));
  17025. },
  17026. ...visibility
  17027. },
  17028. lazyViewport: comp => {
  17029. const win$1 = win();
  17030. const offset = getStickyToolbarOffset(editor);
  17031. const top = win$1.y + (isDockedMode(comp, 'top') ? offset : 0);
  17032. const height = win$1.height - (isDockedMode(comp, 'bottom') ? offset : 0);
  17033. return bounds(win$1.x, top, win$1.width, height);
  17034. },
  17035. modes: [sharedBackstage.header.getDockingMode()],
  17036. onDocked: onDockingSwitch,
  17037. onUndocked: onDockingSwitch
  17038. }),
  17039. ...additionalBehaviours
  17040. ];
  17041. };
  17042. var StickyHeader = /*#__PURE__*/Object.freeze({
  17043. __proto__: null,
  17044. setup: setup$9,
  17045. isDocked: isDocked,
  17046. getBehaviours: getBehaviours
  17047. });
  17048. const renderHeader = spec => {
  17049. const editor = spec.editor;
  17050. const getBehaviours$2 = spec.sticky ? getBehaviours : getBehaviours$1;
  17051. return {
  17052. uid: spec.uid,
  17053. dom: spec.dom,
  17054. components: spec.components,
  17055. behaviours: derive$1(getBehaviours$2(editor, spec.sharedBackstage))
  17056. };
  17057. };
  17058. const groupToolbarButtonSchema = objOf([
  17059. type,
  17060. requiredOf('items', oneOf([
  17061. arrOfObj([
  17062. name$1,
  17063. requiredArrayOf('items', string)
  17064. ]),
  17065. string
  17066. ]))
  17067. ].concat(baseToolbarButtonFields));
  17068. const createGroupToolbarButton = spec => asRaw('GroupToolbarButton', groupToolbarButtonSchema, spec);
  17069. const baseMenuButtonFields = [
  17070. optionString('text'),
  17071. optionString('tooltip'),
  17072. optionString('icon'),
  17073. requiredFunction('fetch'),
  17074. defaultedFunction('onSetup', () => noop)
  17075. ];
  17076. const MenuButtonSchema = objOf([
  17077. type,
  17078. ...baseMenuButtonFields
  17079. ]);
  17080. const createMenuButton = spec => asRaw('menubutton', MenuButtonSchema, spec);
  17081. const splitButtonSchema = objOf([
  17082. type,
  17083. optionalTooltip,
  17084. optionalIcon,
  17085. optionalText,
  17086. optionalSelect,
  17087. fetch$1,
  17088. onSetup,
  17089. defaultedStringEnum('presets', 'normal', [
  17090. 'normal',
  17091. 'color',
  17092. 'listpreview'
  17093. ]),
  17094. defaultedColumns(1),
  17095. onAction,
  17096. onItemAction
  17097. ]);
  17098. const createSplitButton = spec => asRaw('SplitButton', splitButtonSchema, spec);
  17099. const factory$b = (detail, spec) => {
  17100. const setMenus = (comp, menus) => {
  17101. const newMenus = map$2(menus, m => {
  17102. const buttonSpec = {
  17103. type: 'menubutton',
  17104. text: m.text,
  17105. fetch: callback => {
  17106. callback(m.getItems());
  17107. }
  17108. };
  17109. const internal = createMenuButton(buttonSpec).mapError(errInfo => formatError(errInfo)).getOrDie();
  17110. return renderMenuButton(internal, 'tox-mbtn', spec.backstage, Optional.some('menuitem'));
  17111. });
  17112. Replacing.set(comp, newMenus);
  17113. };
  17114. const apis = {
  17115. focus: Keying.focusIn,
  17116. setMenus
  17117. };
  17118. return {
  17119. uid: detail.uid,
  17120. dom: detail.dom,
  17121. components: [],
  17122. behaviours: derive$1([
  17123. Replacing.config({}),
  17124. config('menubar-events', [
  17125. runOnAttached(component => {
  17126. detail.onSetup(component);
  17127. }),
  17128. run$1(mouseover(), (comp, se) => {
  17129. descendant(comp.element, '.' + 'tox-mbtn--active').each(activeButton => {
  17130. closest$1(se.event.target, '.' + 'tox-mbtn').each(hoveredButton => {
  17131. if (!eq(activeButton, hoveredButton)) {
  17132. comp.getSystem().getByDom(activeButton).each(activeComp => {
  17133. comp.getSystem().getByDom(hoveredButton).each(hoveredComp => {
  17134. Dropdown.expand(hoveredComp);
  17135. Dropdown.close(activeComp);
  17136. Focusing.focus(hoveredComp);
  17137. });
  17138. });
  17139. }
  17140. });
  17141. });
  17142. }),
  17143. run$1(focusShifted(), (comp, se) => {
  17144. se.event.prevFocus.bind(prev => comp.getSystem().getByDom(prev).toOptional()).each(prev => {
  17145. se.event.newFocus.bind(nu => comp.getSystem().getByDom(nu).toOptional()).each(nu => {
  17146. if (Dropdown.isOpen(prev)) {
  17147. Dropdown.expand(nu);
  17148. Dropdown.close(prev);
  17149. }
  17150. });
  17151. });
  17152. })
  17153. ]),
  17154. Keying.config({
  17155. mode: 'flow',
  17156. selector: '.' + 'tox-mbtn',
  17157. onEscape: comp => {
  17158. detail.onEscape(comp);
  17159. return Optional.some(true);
  17160. }
  17161. }),
  17162. Tabstopping.config({})
  17163. ]),
  17164. apis,
  17165. domModification: { attributes: { role: 'menubar' } }
  17166. };
  17167. };
  17168. var SilverMenubar = single({
  17169. factory: factory$b,
  17170. name: 'silver.Menubar',
  17171. configFields: [
  17172. required$1('dom'),
  17173. required$1('uid'),
  17174. required$1('onEscape'),
  17175. required$1('backstage'),
  17176. defaulted('onSetup', noop)
  17177. ],
  17178. apis: {
  17179. focus: (apis, comp) => {
  17180. apis.focus(comp);
  17181. },
  17182. setMenus: (apis, comp, menus) => {
  17183. apis.setMenus(comp, menus);
  17184. }
  17185. }
  17186. });
  17187. const getAnimationRoot = (component, slideConfig) => slideConfig.getAnimationRoot.fold(() => component.element, get => get(component));
  17188. const getDimensionProperty = slideConfig => slideConfig.dimension.property;
  17189. const getDimension = (slideConfig, elem) => slideConfig.dimension.getDimension(elem);
  17190. const disableTransitions = (component, slideConfig) => {
  17191. const root = getAnimationRoot(component, slideConfig);
  17192. remove$1(root, [
  17193. slideConfig.shrinkingClass,
  17194. slideConfig.growingClass
  17195. ]);
  17196. };
  17197. const setShrunk = (component, slideConfig) => {
  17198. remove$2(component.element, slideConfig.openClass);
  17199. add$2(component.element, slideConfig.closedClass);
  17200. set$8(component.element, getDimensionProperty(slideConfig), '0px');
  17201. reflow(component.element);
  17202. };
  17203. const setGrown = (component, slideConfig) => {
  17204. remove$2(component.element, slideConfig.closedClass);
  17205. add$2(component.element, slideConfig.openClass);
  17206. remove$6(component.element, getDimensionProperty(slideConfig));
  17207. };
  17208. const doImmediateShrink = (component, slideConfig, slideState, _calculatedSize) => {
  17209. slideState.setCollapsed();
  17210. set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
  17211. disableTransitions(component, slideConfig);
  17212. setShrunk(component, slideConfig);
  17213. slideConfig.onStartShrink(component);
  17214. slideConfig.onShrunk(component);
  17215. };
  17216. const doStartShrink = (component, slideConfig, slideState, calculatedSize) => {
  17217. const size = calculatedSize.getOrThunk(() => getDimension(slideConfig, component.element));
  17218. slideState.setCollapsed();
  17219. set$8(component.element, getDimensionProperty(slideConfig), size);
  17220. reflow(component.element);
  17221. const root = getAnimationRoot(component, slideConfig);
  17222. remove$2(root, slideConfig.growingClass);
  17223. add$2(root, slideConfig.shrinkingClass);
  17224. setShrunk(component, slideConfig);
  17225. slideConfig.onStartShrink(component);
  17226. };
  17227. const doStartSmartShrink = (component, slideConfig, slideState) => {
  17228. const size = getDimension(slideConfig, component.element);
  17229. const shrinker = size === '0px' ? doImmediateShrink : doStartShrink;
  17230. shrinker(component, slideConfig, slideState, Optional.some(size));
  17231. };
  17232. const doStartGrow = (component, slideConfig, slideState) => {
  17233. const root = getAnimationRoot(component, slideConfig);
  17234. const wasShrinking = has(root, slideConfig.shrinkingClass);
  17235. const beforeSize = getDimension(slideConfig, component.element);
  17236. setGrown(component, slideConfig);
  17237. const fullSize = getDimension(slideConfig, component.element);
  17238. const startPartialGrow = () => {
  17239. set$8(component.element, getDimensionProperty(slideConfig), beforeSize);
  17240. reflow(component.element);
  17241. };
  17242. const startCompleteGrow = () => {
  17243. setShrunk(component, slideConfig);
  17244. };
  17245. const setStartSize = wasShrinking ? startPartialGrow : startCompleteGrow;
  17246. setStartSize();
  17247. remove$2(root, slideConfig.shrinkingClass);
  17248. add$2(root, slideConfig.growingClass);
  17249. setGrown(component, slideConfig);
  17250. set$8(component.element, getDimensionProperty(slideConfig), fullSize);
  17251. slideState.setExpanded();
  17252. slideConfig.onStartGrow(component);
  17253. };
  17254. const refresh$3 = (component, slideConfig, slideState) => {
  17255. if (slideState.isExpanded()) {
  17256. remove$6(component.element, getDimensionProperty(slideConfig));
  17257. const fullSize = getDimension(slideConfig, component.element);
  17258. set$8(component.element, getDimensionProperty(slideConfig), fullSize);
  17259. }
  17260. };
  17261. const grow = (component, slideConfig, slideState) => {
  17262. if (!slideState.isExpanded()) {
  17263. doStartGrow(component, slideConfig, slideState);
  17264. }
  17265. };
  17266. const shrink = (component, slideConfig, slideState) => {
  17267. if (slideState.isExpanded()) {
  17268. doStartSmartShrink(component, slideConfig, slideState);
  17269. }
  17270. };
  17271. const immediateShrink = (component, slideConfig, slideState) => {
  17272. if (slideState.isExpanded()) {
  17273. doImmediateShrink(component, slideConfig, slideState);
  17274. }
  17275. };
  17276. const hasGrown = (component, slideConfig, slideState) => slideState.isExpanded();
  17277. const hasShrunk = (component, slideConfig, slideState) => slideState.isCollapsed();
  17278. const isGrowing = (component, slideConfig, _slideState) => {
  17279. const root = getAnimationRoot(component, slideConfig);
  17280. return has(root, slideConfig.growingClass) === true;
  17281. };
  17282. const isShrinking = (component, slideConfig, _slideState) => {
  17283. const root = getAnimationRoot(component, slideConfig);
  17284. return has(root, slideConfig.shrinkingClass) === true;
  17285. };
  17286. const isTransitioning = (component, slideConfig, slideState) => isGrowing(component, slideConfig) || isShrinking(component, slideConfig);
  17287. const toggleGrow = (component, slideConfig, slideState) => {
  17288. const f = slideState.isExpanded() ? doStartSmartShrink : doStartGrow;
  17289. f(component, slideConfig, slideState);
  17290. };
  17291. const immediateGrow = (component, slideConfig, slideState) => {
  17292. if (!slideState.isExpanded()) {
  17293. setGrown(component, slideConfig);
  17294. set$8(component.element, getDimensionProperty(slideConfig), getDimension(slideConfig, component.element));
  17295. disableTransitions(component, slideConfig);
  17296. slideState.setExpanded();
  17297. slideConfig.onStartGrow(component);
  17298. slideConfig.onGrown(component);
  17299. }
  17300. };
  17301. var SlidingApis = /*#__PURE__*/Object.freeze({
  17302. __proto__: null,
  17303. refresh: refresh$3,
  17304. grow: grow,
  17305. shrink: shrink,
  17306. immediateShrink: immediateShrink,
  17307. hasGrown: hasGrown,
  17308. hasShrunk: hasShrunk,
  17309. isGrowing: isGrowing,
  17310. isShrinking: isShrinking,
  17311. isTransitioning: isTransitioning,
  17312. toggleGrow: toggleGrow,
  17313. disableTransitions: disableTransitions,
  17314. immediateGrow: immediateGrow
  17315. });
  17316. const exhibit = (base, slideConfig, _slideState) => {
  17317. const expanded = slideConfig.expanded;
  17318. return expanded ? nu$7({
  17319. classes: [slideConfig.openClass],
  17320. styles: {}
  17321. }) : nu$7({
  17322. classes: [slideConfig.closedClass],
  17323. styles: wrap$1(slideConfig.dimension.property, '0px')
  17324. });
  17325. };
  17326. const events$4 = (slideConfig, slideState) => derive$2([runOnSource(transitionend(), (component, simulatedEvent) => {
  17327. const raw = simulatedEvent.event.raw;
  17328. if (raw.propertyName === slideConfig.dimension.property) {
  17329. disableTransitions(component, slideConfig);
  17330. if (slideState.isExpanded()) {
  17331. remove$6(component.element, slideConfig.dimension.property);
  17332. }
  17333. const notify = slideState.isExpanded() ? slideConfig.onGrown : slideConfig.onShrunk;
  17334. notify(component);
  17335. }
  17336. })]);
  17337. var ActiveSliding = /*#__PURE__*/Object.freeze({
  17338. __proto__: null,
  17339. exhibit: exhibit,
  17340. events: events$4
  17341. });
  17342. var SlidingSchema = [
  17343. required$1('closedClass'),
  17344. required$1('openClass'),
  17345. required$1('shrinkingClass'),
  17346. required$1('growingClass'),
  17347. option$3('getAnimationRoot'),
  17348. onHandler('onShrunk'),
  17349. onHandler('onStartShrink'),
  17350. onHandler('onGrown'),
  17351. onHandler('onStartGrow'),
  17352. defaulted('expanded', false),
  17353. requiredOf('dimension', choose$1('property', {
  17354. width: [
  17355. output$1('property', 'width'),
  17356. output$1('getDimension', elem => get$c(elem) + 'px')
  17357. ],
  17358. height: [
  17359. output$1('property', 'height'),
  17360. output$1('getDimension', elem => get$d(elem) + 'px')
  17361. ]
  17362. }))
  17363. ];
  17364. const init$5 = spec => {
  17365. const state = Cell(spec.expanded);
  17366. const readState = () => 'expanded: ' + state.get();
  17367. return nu$8({
  17368. isExpanded: () => state.get() === true,
  17369. isCollapsed: () => state.get() === false,
  17370. setCollapsed: curry(state.set, false),
  17371. setExpanded: curry(state.set, true),
  17372. readState
  17373. });
  17374. };
  17375. var SlidingState = /*#__PURE__*/Object.freeze({
  17376. __proto__: null,
  17377. init: init$5
  17378. });
  17379. const Sliding = create$3({
  17380. fields: SlidingSchema,
  17381. name: 'sliding',
  17382. active: ActiveSliding,
  17383. apis: SlidingApis,
  17384. state: SlidingState
  17385. });
  17386. const owner = 'container';
  17387. const schema$d = [field('slotBehaviours', [])];
  17388. const getPartName = name => '<alloy.field.' + name + '>';
  17389. const sketch = sSpec => {
  17390. const parts = (() => {
  17391. const record = [];
  17392. const slot = (name, config) => {
  17393. record.push(name);
  17394. return generateOne$1(owner, getPartName(name), config);
  17395. };
  17396. return {
  17397. slot,
  17398. record: constant$1(record)
  17399. };
  17400. })();
  17401. const spec = sSpec(parts);
  17402. const partNames = parts.record();
  17403. const fieldParts = map$2(partNames, n => required({
  17404. name: n,
  17405. pname: getPartName(n)
  17406. }));
  17407. return composite$1(owner, schema$d, fieldParts, make$1, spec);
  17408. };
  17409. const make$1 = (detail, components) => {
  17410. const getSlotNames = _ => getAllPartNames(detail);
  17411. const getSlot = (container, key) => getPart(container, detail, key);
  17412. const onSlot = (f, def) => (container, key) => getPart(container, detail, key).map(slot => f(slot, key)).getOr(def);
  17413. const onSlots = f => (container, keys) => {
  17414. each$1(keys, key => f(container, key));
  17415. };
  17416. const doShowing = (comp, _key) => get$f(comp.element, 'aria-hidden') !== 'true';
  17417. const doShow = (comp, key) => {
  17418. if (!doShowing(comp)) {
  17419. const element = comp.element;
  17420. remove$6(element, 'display');
  17421. remove$7(element, 'aria-hidden');
  17422. emitWith(comp, slotVisibility(), {
  17423. name: key,
  17424. visible: true
  17425. });
  17426. }
  17427. };
  17428. const doHide = (comp, key) => {
  17429. if (doShowing(comp)) {
  17430. const element = comp.element;
  17431. set$8(element, 'display', 'none');
  17432. set$9(element, 'aria-hidden', 'true');
  17433. emitWith(comp, slotVisibility(), {
  17434. name: key,
  17435. visible: false
  17436. });
  17437. }
  17438. };
  17439. const isShowing = onSlot(doShowing, false);
  17440. const hideSlot = onSlot(doHide);
  17441. const hideSlots = onSlots(hideSlot);
  17442. const hideAllSlots = container => hideSlots(container, getSlotNames());
  17443. const showSlot = onSlot(doShow);
  17444. const apis = {
  17445. getSlotNames,
  17446. getSlot,
  17447. isShowing,
  17448. hideSlot,
  17449. hideAllSlots,
  17450. showSlot
  17451. };
  17452. return {
  17453. uid: detail.uid,
  17454. dom: detail.dom,
  17455. components,
  17456. behaviours: get$3(detail.slotBehaviours),
  17457. apis
  17458. };
  17459. };
  17460. const slotApis = map$1({
  17461. getSlotNames: (apis, c) => apis.getSlotNames(c),
  17462. getSlot: (apis, c, key) => apis.getSlot(c, key),
  17463. isShowing: (apis, c, key) => apis.isShowing(c, key),
  17464. hideSlot: (apis, c, key) => apis.hideSlot(c, key),
  17465. hideAllSlots: (apis, c) => apis.hideAllSlots(c),
  17466. showSlot: (apis, c, key) => apis.showSlot(c, key)
  17467. }, value => makeApi(value));
  17468. const SlotContainer = {
  17469. ...slotApis,
  17470. ...{ sketch }
  17471. };
  17472. const sidebarSchema = objOf([
  17473. optionalIcon,
  17474. optionalTooltip,
  17475. defaultedFunction('onShow', noop),
  17476. defaultedFunction('onHide', noop),
  17477. onSetup
  17478. ]);
  17479. const createSidebar = spec => asRaw('sidebar', sidebarSchema, spec);
  17480. const setup$8 = editor => {
  17481. const {sidebars} = editor.ui.registry.getAll();
  17482. each$1(keys(sidebars), name => {
  17483. const spec = sidebars[name];
  17484. const isActive = () => is$1(Optional.from(editor.queryCommandValue('ToggleSidebar')), name);
  17485. editor.ui.registry.addToggleButton(name, {
  17486. icon: spec.icon,
  17487. tooltip: spec.tooltip,
  17488. onAction: buttonApi => {
  17489. editor.execCommand('ToggleSidebar', false, name);
  17490. buttonApi.setActive(isActive());
  17491. },
  17492. onSetup: buttonApi => {
  17493. const handleToggle = () => buttonApi.setActive(isActive());
  17494. editor.on('ToggleSidebar', handleToggle);
  17495. return () => {
  17496. editor.off('ToggleSidebar', handleToggle);
  17497. };
  17498. }
  17499. });
  17500. });
  17501. };
  17502. const getApi = comp => ({ element: () => comp.element.dom });
  17503. const makePanels = (parts, panelConfigs) => {
  17504. const specs = map$2(keys(panelConfigs), name => {
  17505. const spec = panelConfigs[name];
  17506. const bridged = getOrDie(createSidebar(spec));
  17507. return {
  17508. name,
  17509. getApi,
  17510. onSetup: bridged.onSetup,
  17511. onShow: bridged.onShow,
  17512. onHide: bridged.onHide
  17513. };
  17514. });
  17515. return map$2(specs, spec => {
  17516. const editorOffCell = Cell(noop);
  17517. return parts.slot(spec.name, {
  17518. dom: {
  17519. tag: 'div',
  17520. classes: ['tox-sidebar__pane']
  17521. },
  17522. behaviours: SimpleBehaviours.unnamedEvents([
  17523. onControlAttached(spec, editorOffCell),
  17524. onControlDetached(spec, editorOffCell),
  17525. run$1(slotVisibility(), (sidepanel, se) => {
  17526. const data = se.event;
  17527. const optSidePanelSpec = find$5(specs, config => config.name === data.name);
  17528. optSidePanelSpec.each(sidePanelSpec => {
  17529. const handler = data.visible ? sidePanelSpec.onShow : sidePanelSpec.onHide;
  17530. handler(sidePanelSpec.getApi(sidepanel));
  17531. });
  17532. })
  17533. ])
  17534. });
  17535. });
  17536. };
  17537. const makeSidebar = panelConfigs => SlotContainer.sketch(parts => ({
  17538. dom: {
  17539. tag: 'div',
  17540. classes: ['tox-sidebar__pane-container']
  17541. },
  17542. components: makePanels(parts, panelConfigs),
  17543. slotBehaviours: SimpleBehaviours.unnamedEvents([runOnAttached(slotContainer => SlotContainer.hideAllSlots(slotContainer))])
  17544. }));
  17545. const setSidebar = (sidebar, panelConfigs, showSidebar) => {
  17546. const optSlider = Composing.getCurrent(sidebar);
  17547. optSlider.each(slider => {
  17548. Replacing.set(slider, [makeSidebar(panelConfigs)]);
  17549. const configKey = showSidebar === null || showSidebar === void 0 ? void 0 : showSidebar.toLowerCase();
  17550. if (isString(showSidebar) && has$2(panelConfigs, configKey)) {
  17551. Composing.getCurrent(slider).each(slotContainer => {
  17552. SlotContainer.showSlot(slotContainer, configKey);
  17553. Sliding.immediateGrow(slider);
  17554. remove$6(slider.element, 'width');
  17555. });
  17556. }
  17557. });
  17558. };
  17559. const toggleSidebar = (sidebar, name) => {
  17560. const optSlider = Composing.getCurrent(sidebar);
  17561. optSlider.each(slider => {
  17562. const optSlotContainer = Composing.getCurrent(slider);
  17563. optSlotContainer.each(slotContainer => {
  17564. if (Sliding.hasGrown(slider)) {
  17565. if (SlotContainer.isShowing(slotContainer, name)) {
  17566. Sliding.shrink(slider);
  17567. } else {
  17568. SlotContainer.hideAllSlots(slotContainer);
  17569. SlotContainer.showSlot(slotContainer, name);
  17570. }
  17571. } else {
  17572. SlotContainer.hideAllSlots(slotContainer);
  17573. SlotContainer.showSlot(slotContainer, name);
  17574. Sliding.grow(slider);
  17575. }
  17576. });
  17577. });
  17578. };
  17579. const whichSidebar = sidebar => {
  17580. const optSlider = Composing.getCurrent(sidebar);
  17581. return optSlider.bind(slider => {
  17582. const sidebarOpen = Sliding.isGrowing(slider) || Sliding.hasGrown(slider);
  17583. if (sidebarOpen) {
  17584. const optSlotContainer = Composing.getCurrent(slider);
  17585. return optSlotContainer.bind(slotContainer => find$5(SlotContainer.getSlotNames(slotContainer), name => SlotContainer.isShowing(slotContainer, name)));
  17586. } else {
  17587. return Optional.none();
  17588. }
  17589. });
  17590. };
  17591. const fixSize = generate$6('FixSizeEvent');
  17592. const autoSize = generate$6('AutoSizeEvent');
  17593. const renderSidebar = spec => ({
  17594. uid: spec.uid,
  17595. dom: {
  17596. tag: 'div',
  17597. classes: ['tox-sidebar'],
  17598. attributes: { role: 'complementary' }
  17599. },
  17600. components: [{
  17601. dom: {
  17602. tag: 'div',
  17603. classes: ['tox-sidebar__slider']
  17604. },
  17605. components: [],
  17606. behaviours: derive$1([
  17607. Tabstopping.config({}),
  17608. Focusing.config({}),
  17609. Sliding.config({
  17610. dimension: { property: 'width' },
  17611. closedClass: 'tox-sidebar--sliding-closed',
  17612. openClass: 'tox-sidebar--sliding-open',
  17613. shrinkingClass: 'tox-sidebar--sliding-shrinking',
  17614. growingClass: 'tox-sidebar--sliding-growing',
  17615. onShrunk: slider => {
  17616. const optSlotContainer = Composing.getCurrent(slider);
  17617. optSlotContainer.each(SlotContainer.hideAllSlots);
  17618. emit(slider, autoSize);
  17619. },
  17620. onGrown: slider => {
  17621. emit(slider, autoSize);
  17622. },
  17623. onStartGrow: slider => {
  17624. emitWith(slider, fixSize, { width: getRaw(slider.element, 'width').getOr('') });
  17625. },
  17626. onStartShrink: slider => {
  17627. emitWith(slider, fixSize, { width: get$c(slider.element) + 'px' });
  17628. }
  17629. }),
  17630. Replacing.config({}),
  17631. Composing.config({
  17632. find: comp => {
  17633. const children = Replacing.contents(comp);
  17634. return head(children);
  17635. }
  17636. })
  17637. ])
  17638. }],
  17639. behaviours: derive$1([
  17640. ComposingConfigs.childAt(0),
  17641. config('sidebar-sliding-events', [
  17642. run$1(fixSize, (comp, se) => {
  17643. set$8(comp.element, 'width', se.event.width);
  17644. }),
  17645. run$1(autoSize, (comp, _se) => {
  17646. remove$6(comp.element, 'width');
  17647. })
  17648. ])
  17649. ])
  17650. });
  17651. const block = (component, config, state, getBusySpec) => {
  17652. set$9(component.element, 'aria-busy', true);
  17653. const root = config.getRoot(component).getOr(component);
  17654. const blockerBehaviours = derive$1([
  17655. Keying.config({
  17656. mode: 'special',
  17657. onTab: () => Optional.some(true),
  17658. onShiftTab: () => Optional.some(true)
  17659. }),
  17660. Focusing.config({})
  17661. ]);
  17662. const blockSpec = getBusySpec(root, blockerBehaviours);
  17663. const blocker = root.getSystem().build(blockSpec);
  17664. Replacing.append(root, premade(blocker));
  17665. if (blocker.hasConfigured(Keying) && config.focus) {
  17666. Keying.focusIn(blocker);
  17667. }
  17668. if (!state.isBlocked()) {
  17669. config.onBlock(component);
  17670. }
  17671. state.blockWith(() => Replacing.remove(root, blocker));
  17672. };
  17673. const unblock = (component, config, state) => {
  17674. remove$7(component.element, 'aria-busy');
  17675. if (state.isBlocked()) {
  17676. config.onUnblock(component);
  17677. }
  17678. state.clear();
  17679. };
  17680. var BlockingApis = /*#__PURE__*/Object.freeze({
  17681. __proto__: null,
  17682. block: block,
  17683. unblock: unblock
  17684. });
  17685. var BlockingSchema = [
  17686. defaultedFunction('getRoot', Optional.none),
  17687. defaultedBoolean('focus', true),
  17688. onHandler('onBlock'),
  17689. onHandler('onUnblock')
  17690. ];
  17691. const init$4 = () => {
  17692. const blocker = destroyable();
  17693. const blockWith = destroy => {
  17694. blocker.set({ destroy });
  17695. };
  17696. return nu$8({
  17697. readState: blocker.isSet,
  17698. blockWith,
  17699. clear: blocker.clear,
  17700. isBlocked: blocker.isSet
  17701. });
  17702. };
  17703. var BlockingState = /*#__PURE__*/Object.freeze({
  17704. __proto__: null,
  17705. init: init$4
  17706. });
  17707. const Blocking = create$3({
  17708. fields: BlockingSchema,
  17709. name: 'blocking',
  17710. apis: BlockingApis,
  17711. state: BlockingState
  17712. });
  17713. const getAttrs = elem => {
  17714. const attributes = elem.dom.attributes !== undefined ? elem.dom.attributes : [];
  17715. return foldl(attributes, (b, attr) => {
  17716. if (attr.name === 'class') {
  17717. return b;
  17718. } else {
  17719. return {
  17720. ...b,
  17721. [attr.name]: attr.value
  17722. };
  17723. }
  17724. }, {});
  17725. };
  17726. const getClasses = elem => Array.prototype.slice.call(elem.dom.classList, 0);
  17727. const fromHtml = html => {
  17728. const elem = SugarElement.fromHtml(html);
  17729. const children$1 = children(elem);
  17730. const attrs = getAttrs(elem);
  17731. const classes = getClasses(elem);
  17732. const contents = children$1.length === 0 ? {} : { innerHtml: get$9(elem) };
  17733. return {
  17734. tag: name$3(elem),
  17735. classes,
  17736. attributes: attrs,
  17737. ...contents
  17738. };
  17739. };
  17740. const getBusySpec$1 = providerBackstage => (_root, _behaviours) => ({
  17741. dom: {
  17742. tag: 'div',
  17743. attributes: {
  17744. 'aria-label': providerBackstage.translate('Loading...'),
  17745. 'tabindex': '0'
  17746. },
  17747. classes: ['tox-throbber__busy-spinner']
  17748. },
  17749. components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  17750. });
  17751. const focusBusyComponent = throbber => Composing.getCurrent(throbber).each(comp => focus$3(comp.element));
  17752. const toggleEditorTabIndex = (editor, state) => {
  17753. const tabIndexAttr = 'tabindex';
  17754. const dataTabIndexAttr = `data-mce-${ tabIndexAttr }`;
  17755. Optional.from(editor.iframeElement).map(SugarElement.fromDom).each(iframe => {
  17756. if (state) {
  17757. getOpt(iframe, tabIndexAttr).each(tabIndex => set$9(iframe, dataTabIndexAttr, tabIndex));
  17758. set$9(iframe, tabIndexAttr, -1);
  17759. } else {
  17760. remove$7(iframe, tabIndexAttr);
  17761. getOpt(iframe, dataTabIndexAttr).each(tabIndex => {
  17762. set$9(iframe, tabIndexAttr, tabIndex);
  17763. remove$7(iframe, dataTabIndexAttr);
  17764. });
  17765. }
  17766. });
  17767. };
  17768. const toggleThrobber = (editor, comp, state, providerBackstage) => {
  17769. const element = comp.element;
  17770. toggleEditorTabIndex(editor, state);
  17771. if (state) {
  17772. Blocking.block(comp, getBusySpec$1(providerBackstage));
  17773. remove$6(element, 'display');
  17774. remove$7(element, 'aria-hidden');
  17775. if (editor.hasFocus()) {
  17776. focusBusyComponent(comp);
  17777. }
  17778. } else {
  17779. const throbberFocus = Composing.getCurrent(comp).exists(busyComp => hasFocus(busyComp.element));
  17780. Blocking.unblock(comp);
  17781. set$8(element, 'display', 'none');
  17782. set$9(element, 'aria-hidden', 'true');
  17783. if (throbberFocus) {
  17784. editor.focus();
  17785. }
  17786. }
  17787. };
  17788. const renderThrobber = spec => ({
  17789. uid: spec.uid,
  17790. dom: {
  17791. tag: 'div',
  17792. attributes: { 'aria-hidden': 'true' },
  17793. classes: ['tox-throbber'],
  17794. styles: { display: 'none' }
  17795. },
  17796. behaviours: derive$1([
  17797. Replacing.config({}),
  17798. Blocking.config({ focus: false }),
  17799. Composing.config({ find: comp => head(comp.components()) })
  17800. ]),
  17801. components: []
  17802. });
  17803. const isFocusEvent = event => event.type === 'focusin';
  17804. const isPasteBinTarget = event => {
  17805. if (isFocusEvent(event)) {
  17806. const node = event.composed ? head(event.composedPath()) : Optional.from(event.target);
  17807. return node.map(SugarElement.fromDom).filter(isElement$1).exists(targetElm => has(targetElm, 'mce-pastebin'));
  17808. } else {
  17809. return false;
  17810. }
  17811. };
  17812. const setup$7 = (editor, lazyThrobber, sharedBackstage) => {
  17813. const throbberState = Cell(false);
  17814. const timer = value$2();
  17815. const stealFocus = e => {
  17816. if (throbberState.get() && !isPasteBinTarget(e)) {
  17817. e.preventDefault();
  17818. focusBusyComponent(lazyThrobber());
  17819. editor.editorManager.setActive(editor);
  17820. }
  17821. };
  17822. if (!editor.inline) {
  17823. editor.on('PreInit', () => {
  17824. editor.dom.bind(editor.getWin(), 'focusin', stealFocus);
  17825. editor.on('BeforeExecCommand', e => {
  17826. if (e.command.toLowerCase() === 'mcefocus' && e.value !== true) {
  17827. stealFocus(e);
  17828. }
  17829. });
  17830. });
  17831. }
  17832. const toggle = state => {
  17833. if (state !== throbberState.get()) {
  17834. throbberState.set(state);
  17835. toggleThrobber(editor, lazyThrobber(), state, sharedBackstage.providers);
  17836. editor.dispatch('AfterProgressState', { state });
  17837. }
  17838. };
  17839. editor.on('ProgressState', e => {
  17840. timer.on(clearTimeout);
  17841. if (isNumber(e.time)) {
  17842. const timerId = global$9.setEditorTimeout(editor, () => toggle(e.state), e.time);
  17843. timer.set(timerId);
  17844. } else {
  17845. toggle(e.state);
  17846. timer.clear();
  17847. }
  17848. });
  17849. };
  17850. const generate$1 = (xs, f) => {
  17851. const init = {
  17852. len: 0,
  17853. list: []
  17854. };
  17855. const r = foldl(xs, (b, a) => {
  17856. const value = f(a, b.len);
  17857. return value.fold(constant$1(b), v => ({
  17858. len: v.finish,
  17859. list: b.list.concat([v])
  17860. }));
  17861. }, init);
  17862. return r.list;
  17863. };
  17864. const output = (within, extra, withinWidth) => ({
  17865. within,
  17866. extra,
  17867. withinWidth
  17868. });
  17869. const apportion = (units, total, len) => {
  17870. const parray = generate$1(units, (unit, current) => {
  17871. const width = len(unit);
  17872. return Optional.some({
  17873. element: unit,
  17874. start: current,
  17875. finish: current + width,
  17876. width
  17877. });
  17878. });
  17879. const within = filter$2(parray, unit => unit.finish <= total);
  17880. const withinWidth = foldr(within, (acc, el) => acc + el.width, 0);
  17881. const extra = parray.slice(within.length);
  17882. return {
  17883. within,
  17884. extra,
  17885. withinWidth
  17886. };
  17887. };
  17888. const toUnit = parray => map$2(parray, unit => unit.element);
  17889. const fitLast = (within, extra, withinWidth) => {
  17890. const fits = toUnit(within.concat(extra));
  17891. return output(fits, [], withinWidth);
  17892. };
  17893. const overflow = (within, extra, overflower, withinWidth) => {
  17894. const fits = toUnit(within).concat([overflower]);
  17895. return output(fits, toUnit(extra), withinWidth);
  17896. };
  17897. const fitAll = (within, extra, withinWidth) => output(toUnit(within), [], withinWidth);
  17898. const tryFit = (total, units, len) => {
  17899. const divide = apportion(units, total, len);
  17900. return divide.extra.length === 0 ? Optional.some(divide) : Optional.none();
  17901. };
  17902. const partition = (total, units, len, overflower) => {
  17903. const divide = tryFit(total, units, len).getOrThunk(() => apportion(units, total - len(overflower), len));
  17904. const within = divide.within;
  17905. const extra = divide.extra;
  17906. const withinWidth = divide.withinWidth;
  17907. if (extra.length === 1 && extra[0].width <= len(overflower)) {
  17908. return fitLast(within, extra, withinWidth);
  17909. } else if (extra.length >= 1) {
  17910. return overflow(within, extra, overflower, withinWidth);
  17911. } else {
  17912. return fitAll(within, extra, withinWidth);
  17913. }
  17914. };
  17915. const setGroups$1 = (toolbar, storedGroups) => {
  17916. const bGroups = map$2(storedGroups, g => premade(g));
  17917. Toolbar.setGroups(toolbar, bGroups);
  17918. };
  17919. const findFocusedComp = comps => findMap(comps, comp => search(comp.element).bind(focusedElm => comp.getSystem().getByDom(focusedElm).toOptional()));
  17920. const refresh$2 = (toolbar, detail, setOverflow) => {
  17921. const builtGroups = detail.builtGroups.get();
  17922. if (builtGroups.length === 0) {
  17923. return;
  17924. }
  17925. const primary = getPartOrDie(toolbar, detail, 'primary');
  17926. const overflowGroup = Coupling.getCoupled(toolbar, 'overflowGroup');
  17927. set$8(primary.element, 'visibility', 'hidden');
  17928. const groups = builtGroups.concat([overflowGroup]);
  17929. const focusedComp = findFocusedComp(groups);
  17930. setOverflow([]);
  17931. setGroups$1(primary, groups);
  17932. const availableWidth = get$c(primary.element);
  17933. const overflows = partition(availableWidth, detail.builtGroups.get(), comp => get$c(comp.element), overflowGroup);
  17934. if (overflows.extra.length === 0) {
  17935. Replacing.remove(primary, overflowGroup);
  17936. setOverflow([]);
  17937. } else {
  17938. setGroups$1(primary, overflows.within);
  17939. setOverflow(overflows.extra);
  17940. }
  17941. remove$6(primary.element, 'visibility');
  17942. reflow(primary.element);
  17943. focusedComp.each(Focusing.focus);
  17944. };
  17945. const schema$c = constant$1([
  17946. field('splitToolbarBehaviours', [Coupling]),
  17947. customField('builtGroups', () => Cell([]))
  17948. ]);
  17949. const schema$b = constant$1([
  17950. markers$1(['overflowToggledClass']),
  17951. optionFunction('getOverflowBounds'),
  17952. required$1('lazySink'),
  17953. customField('overflowGroups', () => Cell([]))
  17954. ].concat(schema$c()));
  17955. const parts$7 = constant$1([
  17956. required({
  17957. factory: Toolbar,
  17958. schema: schema$e(),
  17959. name: 'primary'
  17960. }),
  17961. external({
  17962. schema: schema$e(),
  17963. name: 'overflow'
  17964. }),
  17965. external({ name: 'overflow-button' }),
  17966. external({ name: 'overflow-group' })
  17967. ]);
  17968. const expandable = constant$1((element, available) => {
  17969. setMax(element, Math.floor(available));
  17970. });
  17971. const schema$a = constant$1([
  17972. markers$1(['toggledClass']),
  17973. required$1('lazySink'),
  17974. requiredFunction('fetch'),
  17975. optionFunction('getBounds'),
  17976. optionObjOf('fireDismissalEventInstead', [defaulted('event', dismissRequested())]),
  17977. schema$y()
  17978. ]);
  17979. const parts$6 = constant$1([
  17980. external({
  17981. name: 'button',
  17982. overrides: detail => ({
  17983. dom: { attributes: { 'aria-haspopup': 'true' } },
  17984. buttonBehaviours: derive$1([Toggling.config({
  17985. toggleClass: detail.markers.toggledClass,
  17986. aria: { mode: 'expanded' },
  17987. toggleOnExecute: false
  17988. })])
  17989. })
  17990. }),
  17991. external({
  17992. factory: Toolbar,
  17993. schema: schema$e(),
  17994. name: 'toolbar',
  17995. overrides: detail => {
  17996. return {
  17997. toolbarBehaviours: derive$1([Keying.config({
  17998. mode: 'cyclic',
  17999. onEscape: comp => {
  18000. getPart(comp, detail, 'button').each(Focusing.focus);
  18001. return Optional.none();
  18002. }
  18003. })])
  18004. };
  18005. }
  18006. })
  18007. ]);
  18008. const toggle = (button, externals) => {
  18009. const toolbarSandbox = Coupling.getCoupled(button, 'toolbarSandbox');
  18010. if (Sandboxing.isOpen(toolbarSandbox)) {
  18011. Sandboxing.close(toolbarSandbox);
  18012. } else {
  18013. Sandboxing.open(toolbarSandbox, externals.toolbar());
  18014. }
  18015. };
  18016. const position = (button, toolbar, detail, layouts) => {
  18017. const bounds = detail.getBounds.map(bounder => bounder());
  18018. const sink = detail.lazySink(button).getOrDie();
  18019. Positioning.positionWithinBounds(sink, toolbar, {
  18020. anchor: {
  18021. type: 'hotspot',
  18022. hotspot: button,
  18023. layouts,
  18024. overrides: { maxWidthFunction: expandable() }
  18025. }
  18026. }, bounds);
  18027. };
  18028. const setGroups = (button, toolbar, detail, layouts, groups) => {
  18029. Toolbar.setGroups(toolbar, groups);
  18030. position(button, toolbar, detail, layouts);
  18031. Toggling.on(button);
  18032. };
  18033. const makeSandbox = (button, spec, detail) => {
  18034. const ariaControls = manager();
  18035. const onOpen = (sandbox, toolbar) => {
  18036. detail.fetch().get(groups => {
  18037. setGroups(button, toolbar, detail, spec.layouts, groups);
  18038. ariaControls.link(button.element);
  18039. Keying.focusIn(toolbar);
  18040. });
  18041. };
  18042. const onClose = () => {
  18043. Toggling.off(button);
  18044. Focusing.focus(button);
  18045. ariaControls.unlink(button.element);
  18046. };
  18047. return {
  18048. dom: {
  18049. tag: 'div',
  18050. attributes: { id: ariaControls.id }
  18051. },
  18052. behaviours: derive$1([
  18053. Keying.config({
  18054. mode: 'special',
  18055. onEscape: comp => {
  18056. Sandboxing.close(comp);
  18057. return Optional.some(true);
  18058. }
  18059. }),
  18060. Sandboxing.config({
  18061. onOpen,
  18062. onClose,
  18063. isPartOf: (container, data, queryElem) => {
  18064. return isPartOf$1(data, queryElem) || isPartOf$1(button, queryElem);
  18065. },
  18066. getAttachPoint: () => {
  18067. return detail.lazySink(button).getOrDie();
  18068. }
  18069. }),
  18070. Receiving.config({
  18071. channels: {
  18072. ...receivingChannel$1({
  18073. isExtraPart: never,
  18074. ...detail.fireDismissalEventInstead.map(fe => ({ fireEventInstead: { event: fe.event } })).getOr({})
  18075. }),
  18076. ...receivingChannel({
  18077. doReposition: () => {
  18078. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  18079. position(button, toolbar, detail, spec.layouts);
  18080. });
  18081. }
  18082. })
  18083. }
  18084. })
  18085. ])
  18086. };
  18087. };
  18088. const factory$a = (detail, components, spec, externals) => ({
  18089. ...Button.sketch({
  18090. ...externals.button(),
  18091. action: button => {
  18092. toggle(button, externals);
  18093. },
  18094. buttonBehaviours: SketchBehaviours.augment({ dump: externals.button().buttonBehaviours }, [Coupling.config({
  18095. others: {
  18096. toolbarSandbox: button => {
  18097. return makeSandbox(button, spec, detail);
  18098. }
  18099. }
  18100. })])
  18101. }),
  18102. apis: {
  18103. setGroups: (button, groups) => {
  18104. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  18105. setGroups(button, toolbar, detail, spec.layouts, groups);
  18106. });
  18107. },
  18108. reposition: button => {
  18109. Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox')).each(toolbar => {
  18110. position(button, toolbar, detail, spec.layouts);
  18111. });
  18112. },
  18113. toggle: button => {
  18114. toggle(button, externals);
  18115. },
  18116. getToolbar: button => {
  18117. return Sandboxing.getState(Coupling.getCoupled(button, 'toolbarSandbox'));
  18118. },
  18119. isOpen: button => {
  18120. return Sandboxing.isOpen(Coupling.getCoupled(button, 'toolbarSandbox'));
  18121. }
  18122. }
  18123. });
  18124. const FloatingToolbarButton = composite({
  18125. name: 'FloatingToolbarButton',
  18126. factory: factory$a,
  18127. configFields: schema$a(),
  18128. partFields: parts$6(),
  18129. apis: {
  18130. setGroups: (apis, button, groups) => {
  18131. apis.setGroups(button, groups);
  18132. },
  18133. reposition: (apis, button) => {
  18134. apis.reposition(button);
  18135. },
  18136. toggle: (apis, button) => {
  18137. apis.toggle(button);
  18138. },
  18139. getToolbar: (apis, button) => apis.getToolbar(button),
  18140. isOpen: (apis, button) => apis.isOpen(button)
  18141. }
  18142. });
  18143. const schema$9 = constant$1([
  18144. required$1('items'),
  18145. markers$1(['itemSelector']),
  18146. field('tgroupBehaviours', [Keying])
  18147. ]);
  18148. const parts$5 = constant$1([group({
  18149. name: 'items',
  18150. unit: 'item'
  18151. })]);
  18152. const factory$9 = (detail, components, _spec, _externals) => ({
  18153. uid: detail.uid,
  18154. dom: detail.dom,
  18155. components,
  18156. behaviours: augment(detail.tgroupBehaviours, [Keying.config({
  18157. mode: 'flow',
  18158. selector: detail.markers.itemSelector
  18159. })]),
  18160. domModification: { attributes: { role: 'toolbar' } }
  18161. });
  18162. const ToolbarGroup = composite({
  18163. name: 'ToolbarGroup',
  18164. configFields: schema$9(),
  18165. partFields: parts$5(),
  18166. factory: factory$9
  18167. });
  18168. const buildGroups = comps => map$2(comps, g => premade(g));
  18169. const refresh$1 = (toolbar, memFloatingToolbarButton, detail) => {
  18170. refresh$2(toolbar, detail, overflowGroups => {
  18171. detail.overflowGroups.set(overflowGroups);
  18172. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  18173. FloatingToolbarButton.setGroups(floatingToolbarButton, buildGroups(overflowGroups));
  18174. });
  18175. });
  18176. };
  18177. const factory$8 = (detail, components, spec, externals) => {
  18178. const memFloatingToolbarButton = record(FloatingToolbarButton.sketch({
  18179. fetch: () => Future.nu(resolve => {
  18180. resolve(buildGroups(detail.overflowGroups.get()));
  18181. }),
  18182. layouts: {
  18183. onLtr: () => [
  18184. southwest$2,
  18185. southeast$2
  18186. ],
  18187. onRtl: () => [
  18188. southeast$2,
  18189. southwest$2
  18190. ],
  18191. onBottomLtr: () => [
  18192. northwest$2,
  18193. northeast$2
  18194. ],
  18195. onBottomRtl: () => [
  18196. northeast$2,
  18197. northwest$2
  18198. ]
  18199. },
  18200. getBounds: spec.getOverflowBounds,
  18201. lazySink: detail.lazySink,
  18202. fireDismissalEventInstead: {},
  18203. markers: { toggledClass: detail.markers.overflowToggledClass },
  18204. parts: {
  18205. button: externals['overflow-button'](),
  18206. toolbar: externals.overflow()
  18207. }
  18208. }));
  18209. return {
  18210. uid: detail.uid,
  18211. dom: detail.dom,
  18212. components,
  18213. behaviours: augment(detail.splitToolbarBehaviours, [Coupling.config({
  18214. others: {
  18215. overflowGroup: () => {
  18216. return ToolbarGroup.sketch({
  18217. ...externals['overflow-group'](),
  18218. items: [memFloatingToolbarButton.asSpec()]
  18219. });
  18220. }
  18221. }
  18222. })]),
  18223. apis: {
  18224. setGroups: (toolbar, groups) => {
  18225. detail.builtGroups.set(map$2(groups, toolbar.getSystem().build));
  18226. refresh$1(toolbar, memFloatingToolbarButton, detail);
  18227. },
  18228. refresh: toolbar => refresh$1(toolbar, memFloatingToolbarButton, detail),
  18229. toggle: toolbar => {
  18230. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  18231. FloatingToolbarButton.toggle(floatingToolbarButton);
  18232. });
  18233. },
  18234. isOpen: toolbar => memFloatingToolbarButton.getOpt(toolbar).map(FloatingToolbarButton.isOpen).getOr(false),
  18235. reposition: toolbar => {
  18236. memFloatingToolbarButton.getOpt(toolbar).each(floatingToolbarButton => {
  18237. FloatingToolbarButton.reposition(floatingToolbarButton);
  18238. });
  18239. },
  18240. getOverflow: toolbar => memFloatingToolbarButton.getOpt(toolbar).bind(FloatingToolbarButton.getToolbar)
  18241. },
  18242. domModification: { attributes: { role: 'group' } }
  18243. };
  18244. };
  18245. const SplitFloatingToolbar = composite({
  18246. name: 'SplitFloatingToolbar',
  18247. configFields: schema$b(),
  18248. partFields: parts$7(),
  18249. factory: factory$8,
  18250. apis: {
  18251. setGroups: (apis, toolbar, groups) => {
  18252. apis.setGroups(toolbar, groups);
  18253. },
  18254. refresh: (apis, toolbar) => {
  18255. apis.refresh(toolbar);
  18256. },
  18257. reposition: (apis, toolbar) => {
  18258. apis.reposition(toolbar);
  18259. },
  18260. toggle: (apis, toolbar) => {
  18261. apis.toggle(toolbar);
  18262. },
  18263. isOpen: (apis, toolbar) => apis.isOpen(toolbar),
  18264. getOverflow: (apis, toolbar) => apis.getOverflow(toolbar)
  18265. }
  18266. });
  18267. const schema$8 = constant$1([
  18268. markers$1([
  18269. 'closedClass',
  18270. 'openClass',
  18271. 'shrinkingClass',
  18272. 'growingClass',
  18273. 'overflowToggledClass'
  18274. ]),
  18275. onHandler('onOpened'),
  18276. onHandler('onClosed')
  18277. ].concat(schema$c()));
  18278. const parts$4 = constant$1([
  18279. required({
  18280. factory: Toolbar,
  18281. schema: schema$e(),
  18282. name: 'primary'
  18283. }),
  18284. required({
  18285. factory: Toolbar,
  18286. schema: schema$e(),
  18287. name: 'overflow',
  18288. overrides: detail => {
  18289. return {
  18290. toolbarBehaviours: derive$1([
  18291. Sliding.config({
  18292. dimension: { property: 'height' },
  18293. closedClass: detail.markers.closedClass,
  18294. openClass: detail.markers.openClass,
  18295. shrinkingClass: detail.markers.shrinkingClass,
  18296. growingClass: detail.markers.growingClass,
  18297. onShrunk: comp => {
  18298. getPart(comp, detail, 'overflow-button').each(button => {
  18299. Toggling.off(button);
  18300. Focusing.focus(button);
  18301. });
  18302. detail.onClosed(comp);
  18303. },
  18304. onGrown: comp => {
  18305. Keying.focusIn(comp);
  18306. detail.onOpened(comp);
  18307. },
  18308. onStartGrow: comp => {
  18309. getPart(comp, detail, 'overflow-button').each(Toggling.on);
  18310. }
  18311. }),
  18312. Keying.config({
  18313. mode: 'acyclic',
  18314. onEscape: comp => {
  18315. getPart(comp, detail, 'overflow-button').each(Focusing.focus);
  18316. return Optional.some(true);
  18317. }
  18318. })
  18319. ])
  18320. };
  18321. }
  18322. }),
  18323. external({
  18324. name: 'overflow-button',
  18325. overrides: detail => ({
  18326. buttonBehaviours: derive$1([Toggling.config({
  18327. toggleClass: detail.markers.overflowToggledClass,
  18328. aria: { mode: 'pressed' },
  18329. toggleOnExecute: false
  18330. })])
  18331. })
  18332. }),
  18333. external({ name: 'overflow-group' })
  18334. ]);
  18335. const isOpen = (toolbar, detail) => getPart(toolbar, detail, 'overflow').map(Sliding.hasGrown).getOr(false);
  18336. const toggleToolbar = (toolbar, detail) => {
  18337. getPart(toolbar, detail, 'overflow-button').bind(() => getPart(toolbar, detail, 'overflow')).each(overf => {
  18338. refresh(toolbar, detail);
  18339. Sliding.toggleGrow(overf);
  18340. });
  18341. };
  18342. const refresh = (toolbar, detail) => {
  18343. getPart(toolbar, detail, 'overflow').each(overflow => {
  18344. refresh$2(toolbar, detail, groups => {
  18345. const builtGroups = map$2(groups, g => premade(g));
  18346. Toolbar.setGroups(overflow, builtGroups);
  18347. });
  18348. getPart(toolbar, detail, 'overflow-button').each(button => {
  18349. if (Sliding.hasGrown(overflow)) {
  18350. Toggling.on(button);
  18351. }
  18352. });
  18353. Sliding.refresh(overflow);
  18354. });
  18355. };
  18356. const factory$7 = (detail, components, spec, externals) => {
  18357. const toolbarToggleEvent = 'alloy.toolbar.toggle';
  18358. const doSetGroups = (toolbar, groups) => {
  18359. const built = map$2(groups, toolbar.getSystem().build);
  18360. detail.builtGroups.set(built);
  18361. };
  18362. return {
  18363. uid: detail.uid,
  18364. dom: detail.dom,
  18365. components,
  18366. behaviours: augment(detail.splitToolbarBehaviours, [
  18367. Coupling.config({
  18368. others: {
  18369. overflowGroup: toolbar => {
  18370. return ToolbarGroup.sketch({
  18371. ...externals['overflow-group'](),
  18372. items: [Button.sketch({
  18373. ...externals['overflow-button'](),
  18374. action: _button => {
  18375. emit(toolbar, toolbarToggleEvent);
  18376. }
  18377. })]
  18378. });
  18379. }
  18380. }
  18381. }),
  18382. config('toolbar-toggle-events', [run$1(toolbarToggleEvent, toolbar => {
  18383. toggleToolbar(toolbar, detail);
  18384. })])
  18385. ]),
  18386. apis: {
  18387. setGroups: (toolbar, groups) => {
  18388. doSetGroups(toolbar, groups);
  18389. refresh(toolbar, detail);
  18390. },
  18391. refresh: toolbar => refresh(toolbar, detail),
  18392. toggle: toolbar => toggleToolbar(toolbar, detail),
  18393. isOpen: toolbar => isOpen(toolbar, detail)
  18394. },
  18395. domModification: { attributes: { role: 'group' } }
  18396. };
  18397. };
  18398. const SplitSlidingToolbar = composite({
  18399. name: 'SplitSlidingToolbar',
  18400. configFields: schema$8(),
  18401. partFields: parts$4(),
  18402. factory: factory$7,
  18403. apis: {
  18404. setGroups: (apis, toolbar, groups) => {
  18405. apis.setGroups(toolbar, groups);
  18406. },
  18407. refresh: (apis, toolbar) => {
  18408. apis.refresh(toolbar);
  18409. },
  18410. toggle: (apis, toolbar) => {
  18411. apis.toggle(toolbar);
  18412. },
  18413. isOpen: (apis, toolbar) => apis.isOpen(toolbar)
  18414. }
  18415. });
  18416. const renderToolbarGroupCommon = toolbarGroup => {
  18417. const attributes = toolbarGroup.title.fold(() => ({}), title => ({ attributes: { title } }));
  18418. return {
  18419. dom: {
  18420. tag: 'div',
  18421. classes: ['tox-toolbar__group'],
  18422. ...attributes
  18423. },
  18424. components: [ToolbarGroup.parts.items({})],
  18425. items: toolbarGroup.items,
  18426. markers: { itemSelector: '*:not(.tox-split-button) > .tox-tbtn:not([disabled]), ' + '.tox-split-button:not([disabled]), ' + '.tox-toolbar-nav-js:not([disabled])' },
  18427. tgroupBehaviours: derive$1([
  18428. Tabstopping.config({}),
  18429. Focusing.config({})
  18430. ])
  18431. };
  18432. };
  18433. const renderToolbarGroup = toolbarGroup => ToolbarGroup.sketch(renderToolbarGroupCommon(toolbarGroup));
  18434. const getToolbarbehaviours = (toolbarSpec, modeName) => {
  18435. const onAttached = runOnAttached(component => {
  18436. const groups = map$2(toolbarSpec.initGroups, renderToolbarGroup);
  18437. Toolbar.setGroups(component, groups);
  18438. });
  18439. return derive$1([
  18440. DisablingConfigs.toolbarButton(toolbarSpec.providers.isDisabled),
  18441. receivingConfig(),
  18442. Keying.config({
  18443. mode: modeName,
  18444. onEscape: toolbarSpec.onEscape,
  18445. selector: '.tox-toolbar__group'
  18446. }),
  18447. config('toolbar-events', [onAttached])
  18448. ]);
  18449. };
  18450. const renderMoreToolbarCommon = toolbarSpec => {
  18451. const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
  18452. return {
  18453. uid: toolbarSpec.uid,
  18454. dom: {
  18455. tag: 'div',
  18456. classes: ['tox-toolbar-overlord']
  18457. },
  18458. parts: {
  18459. 'overflow-group': renderToolbarGroupCommon({
  18460. title: Optional.none(),
  18461. items: []
  18462. }),
  18463. 'overflow-button': renderIconButtonSpec({
  18464. name: 'more',
  18465. icon: Optional.some('more-drawer'),
  18466. enabled: true,
  18467. tooltip: Optional.some('More...'),
  18468. primary: false,
  18469. buttonType: Optional.none(),
  18470. borderless: false
  18471. }, Optional.none(), toolbarSpec.providers)
  18472. },
  18473. splitToolbarBehaviours: getToolbarbehaviours(toolbarSpec, modeName)
  18474. };
  18475. };
  18476. const renderFloatingMoreToolbar = toolbarSpec => {
  18477. const baseSpec = renderMoreToolbarCommon(toolbarSpec);
  18478. const overflowXOffset = 4;
  18479. const primary = SplitFloatingToolbar.parts.primary({
  18480. dom: {
  18481. tag: 'div',
  18482. classes: ['tox-toolbar__primary']
  18483. }
  18484. });
  18485. return SplitFloatingToolbar.sketch({
  18486. ...baseSpec,
  18487. lazySink: toolbarSpec.getSink,
  18488. getOverflowBounds: () => {
  18489. const headerElem = toolbarSpec.moreDrawerData.lazyHeader().element;
  18490. const headerBounds = absolute$2(headerElem);
  18491. const docElem = documentElement(headerElem);
  18492. const docBounds = absolute$2(docElem);
  18493. const height = Math.max(docElem.dom.scrollHeight, docBounds.height);
  18494. return bounds(headerBounds.x + overflowXOffset, docBounds.y, headerBounds.width - overflowXOffset * 2, height);
  18495. },
  18496. parts: {
  18497. ...baseSpec.parts,
  18498. overflow: {
  18499. dom: {
  18500. tag: 'div',
  18501. classes: ['tox-toolbar__overflow'],
  18502. attributes: toolbarSpec.attributes
  18503. }
  18504. }
  18505. },
  18506. components: [primary],
  18507. markers: { overflowToggledClass: 'tox-tbtn--enabled' }
  18508. });
  18509. };
  18510. const renderSlidingMoreToolbar = toolbarSpec => {
  18511. const primary = SplitSlidingToolbar.parts.primary({
  18512. dom: {
  18513. tag: 'div',
  18514. classes: ['tox-toolbar__primary']
  18515. }
  18516. });
  18517. const overflow = SplitSlidingToolbar.parts.overflow({
  18518. dom: {
  18519. tag: 'div',
  18520. classes: ['tox-toolbar__overflow']
  18521. }
  18522. });
  18523. const baseSpec = renderMoreToolbarCommon(toolbarSpec);
  18524. return SplitSlidingToolbar.sketch({
  18525. ...baseSpec,
  18526. components: [
  18527. primary,
  18528. overflow
  18529. ],
  18530. markers: {
  18531. openClass: 'tox-toolbar__overflow--open',
  18532. closedClass: 'tox-toolbar__overflow--closed',
  18533. growingClass: 'tox-toolbar__overflow--growing',
  18534. shrinkingClass: 'tox-toolbar__overflow--shrinking',
  18535. overflowToggledClass: 'tox-tbtn--enabled'
  18536. },
  18537. onOpened: comp => {
  18538. comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'opened' });
  18539. },
  18540. onClosed: comp => {
  18541. comp.getSystem().broadcastOn([toolbarHeightChange()], { type: 'closed' });
  18542. }
  18543. });
  18544. };
  18545. const renderToolbar = toolbarSpec => {
  18546. const modeName = toolbarSpec.cyclicKeying ? 'cyclic' : 'acyclic';
  18547. return Toolbar.sketch({
  18548. uid: toolbarSpec.uid,
  18549. dom: {
  18550. tag: 'div',
  18551. classes: ['tox-toolbar'].concat(toolbarSpec.type === ToolbarMode$1.scrolling ? ['tox-toolbar--scrolling'] : [])
  18552. },
  18553. components: [Toolbar.parts.groups({})],
  18554. toolbarBehaviours: getToolbarbehaviours(toolbarSpec, modeName)
  18555. });
  18556. };
  18557. const factory$6 = (detail, components, _spec) => {
  18558. const apis = {
  18559. getSocket: comp => {
  18560. return parts$a.getPart(comp, detail, 'socket');
  18561. },
  18562. setSidebar: (comp, panelConfigs, showSidebar) => {
  18563. parts$a.getPart(comp, detail, 'sidebar').each(sidebar => setSidebar(sidebar, panelConfigs, showSidebar));
  18564. },
  18565. toggleSidebar: (comp, name) => {
  18566. parts$a.getPart(comp, detail, 'sidebar').each(sidebar => toggleSidebar(sidebar, name));
  18567. },
  18568. whichSidebar: comp => {
  18569. return parts$a.getPart(comp, detail, 'sidebar').bind(whichSidebar).getOrNull();
  18570. },
  18571. getHeader: comp => {
  18572. return parts$a.getPart(comp, detail, 'header');
  18573. },
  18574. getToolbar: comp => {
  18575. return parts$a.getPart(comp, detail, 'toolbar');
  18576. },
  18577. setToolbar: (comp, groups) => {
  18578. parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
  18579. toolbar.getApis().setGroups(toolbar, groups);
  18580. });
  18581. },
  18582. setToolbars: (comp, toolbars) => {
  18583. parts$a.getPart(comp, detail, 'multiple-toolbar').each(mToolbar => {
  18584. CustomList.setItems(mToolbar, toolbars);
  18585. });
  18586. },
  18587. refreshToolbar: comp => {
  18588. const toolbar = parts$a.getPart(comp, detail, 'toolbar');
  18589. toolbar.each(toolbar => toolbar.getApis().refresh(toolbar));
  18590. },
  18591. toggleToolbarDrawer: comp => {
  18592. parts$a.getPart(comp, detail, 'toolbar').each(toolbar => {
  18593. mapFrom(toolbar.getApis().toggle, toggle => toggle(toolbar));
  18594. });
  18595. },
  18596. isToolbarDrawerToggled: comp => {
  18597. return parts$a.getPart(comp, detail, 'toolbar').bind(toolbar => Optional.from(toolbar.getApis().isOpen).map(isOpen => isOpen(toolbar))).getOr(false);
  18598. },
  18599. getThrobber: comp => {
  18600. return parts$a.getPart(comp, detail, 'throbber');
  18601. },
  18602. focusToolbar: comp => {
  18603. const optToolbar = parts$a.getPart(comp, detail, 'toolbar').orThunk(() => parts$a.getPart(comp, detail, 'multiple-toolbar'));
  18604. optToolbar.each(toolbar => {
  18605. Keying.focusIn(toolbar);
  18606. });
  18607. },
  18608. setMenubar: (comp, menus) => {
  18609. parts$a.getPart(comp, detail, 'menubar').each(menubar => {
  18610. SilverMenubar.setMenus(menubar, menus);
  18611. });
  18612. },
  18613. focusMenubar: comp => {
  18614. parts$a.getPart(comp, detail, 'menubar').each(menubar => {
  18615. SilverMenubar.focus(menubar);
  18616. });
  18617. }
  18618. };
  18619. return {
  18620. uid: detail.uid,
  18621. dom: detail.dom,
  18622. components,
  18623. apis,
  18624. behaviours: detail.behaviours
  18625. };
  18626. };
  18627. const partMenubar = partType.optional({
  18628. factory: SilverMenubar,
  18629. name: 'menubar',
  18630. schema: [required$1('backstage')]
  18631. });
  18632. const toolbarFactory = spec => {
  18633. if (spec.type === ToolbarMode$1.sliding) {
  18634. return renderSlidingMoreToolbar;
  18635. } else if (spec.type === ToolbarMode$1.floating) {
  18636. return renderFloatingMoreToolbar;
  18637. } else {
  18638. return renderToolbar;
  18639. }
  18640. };
  18641. const partMultipleToolbar = partType.optional({
  18642. factory: {
  18643. sketch: spec => CustomList.sketch({
  18644. uid: spec.uid,
  18645. dom: spec.dom,
  18646. listBehaviours: derive$1([Keying.config({
  18647. mode: 'acyclic',
  18648. selector: '.tox-toolbar'
  18649. })]),
  18650. makeItem: () => renderToolbar({
  18651. type: spec.type,
  18652. uid: generate$6('multiple-toolbar-item'),
  18653. cyclicKeying: false,
  18654. initGroups: [],
  18655. providers: spec.providers,
  18656. onEscape: () => {
  18657. spec.onEscape();
  18658. return Optional.some(true);
  18659. }
  18660. }),
  18661. setupItem: (_mToolbar, tc, data, _index) => {
  18662. Toolbar.setGroups(tc, data);
  18663. },
  18664. shell: true
  18665. })
  18666. },
  18667. name: 'multiple-toolbar',
  18668. schema: [
  18669. required$1('dom'),
  18670. required$1('onEscape')
  18671. ]
  18672. });
  18673. const partToolbar = partType.optional({
  18674. factory: {
  18675. sketch: spec => {
  18676. const renderer = toolbarFactory(spec);
  18677. const toolbarSpec = {
  18678. type: spec.type,
  18679. uid: spec.uid,
  18680. onEscape: () => {
  18681. spec.onEscape();
  18682. return Optional.some(true);
  18683. },
  18684. cyclicKeying: false,
  18685. initGroups: [],
  18686. getSink: spec.getSink,
  18687. providers: spec.providers,
  18688. moreDrawerData: {
  18689. lazyToolbar: spec.lazyToolbar,
  18690. lazyMoreButton: spec.lazyMoreButton,
  18691. lazyHeader: spec.lazyHeader
  18692. },
  18693. attributes: spec.attributes
  18694. };
  18695. return renderer(toolbarSpec);
  18696. }
  18697. },
  18698. name: 'toolbar',
  18699. schema: [
  18700. required$1('dom'),
  18701. required$1('onEscape'),
  18702. required$1('getSink')
  18703. ]
  18704. });
  18705. const partHeader = partType.optional({
  18706. factory: { sketch: renderHeader },
  18707. name: 'header',
  18708. schema: [required$1('dom')]
  18709. });
  18710. const partSocket = partType.optional({
  18711. name: 'socket',
  18712. schema: [required$1('dom')]
  18713. });
  18714. const partSidebar = partType.optional({
  18715. factory: { sketch: renderSidebar },
  18716. name: 'sidebar',
  18717. schema: [required$1('dom')]
  18718. });
  18719. const partThrobber = partType.optional({
  18720. factory: { sketch: renderThrobber },
  18721. name: 'throbber',
  18722. schema: [required$1('dom')]
  18723. });
  18724. var OuterContainer = composite({
  18725. name: 'OuterContainer',
  18726. factory: factory$6,
  18727. configFields: [
  18728. required$1('dom'),
  18729. required$1('behaviours')
  18730. ],
  18731. partFields: [
  18732. partHeader,
  18733. partMenubar,
  18734. partToolbar,
  18735. partMultipleToolbar,
  18736. partSocket,
  18737. partSidebar,
  18738. partThrobber
  18739. ],
  18740. apis: {
  18741. getSocket: (apis, comp) => {
  18742. return apis.getSocket(comp);
  18743. },
  18744. setSidebar: (apis, comp, panelConfigs, showSidebar) => {
  18745. apis.setSidebar(comp, panelConfigs, showSidebar);
  18746. },
  18747. toggleSidebar: (apis, comp, name) => {
  18748. apis.toggleSidebar(comp, name);
  18749. },
  18750. whichSidebar: (apis, comp) => {
  18751. return apis.whichSidebar(comp);
  18752. },
  18753. getHeader: (apis, comp) => {
  18754. return apis.getHeader(comp);
  18755. },
  18756. getToolbar: (apis, comp) => {
  18757. return apis.getToolbar(comp);
  18758. },
  18759. setToolbar: (apis, comp, grps) => {
  18760. const groups = map$2(grps, grp => {
  18761. return renderToolbarGroup(grp);
  18762. });
  18763. apis.setToolbar(comp, groups);
  18764. },
  18765. setToolbars: (apis, comp, ts) => {
  18766. const renderedToolbars = map$2(ts, g => map$2(g, renderToolbarGroup));
  18767. apis.setToolbars(comp, renderedToolbars);
  18768. },
  18769. refreshToolbar: (apis, comp) => {
  18770. return apis.refreshToolbar(comp);
  18771. },
  18772. toggleToolbarDrawer: (apis, comp) => {
  18773. apis.toggleToolbarDrawer(comp);
  18774. },
  18775. isToolbarDrawerToggled: (apis, comp) => {
  18776. return apis.isToolbarDrawerToggled(comp);
  18777. },
  18778. getThrobber: (apis, comp) => {
  18779. return apis.getThrobber(comp);
  18780. },
  18781. setMenubar: (apis, comp, menus) => {
  18782. apis.setMenubar(comp, menus);
  18783. },
  18784. focusMenubar: (apis, comp) => {
  18785. apis.focusMenubar(comp);
  18786. },
  18787. focusToolbar: (apis, comp) => {
  18788. apis.focusToolbar(comp);
  18789. }
  18790. }
  18791. });
  18792. const defaultMenubar = 'file edit view insert format tools table help';
  18793. const defaultMenus = {
  18794. file: {
  18795. title: 'File',
  18796. items: 'newdocument restoredraft | preview | export print | deleteallconversations'
  18797. },
  18798. edit: {
  18799. title: 'Edit',
  18800. items: 'undo redo | cut copy paste pastetext | selectall | searchreplace'
  18801. },
  18802. view: {
  18803. title: 'View',
  18804. items: 'code | visualaid visualchars visualblocks | spellchecker | preview fullscreen | showcomments'
  18805. },
  18806. insert: {
  18807. title: 'Insert',
  18808. items: 'image link media addcomment pageembed template codesample inserttable | charmap emoticons hr | pagebreak nonbreaking anchor tableofcontents | insertdatetime'
  18809. },
  18810. format: {
  18811. title: 'Format',
  18812. items: 'bold italic underline strikethrough superscript subscript codeformat | styles blocks fontfamily fontsize align lineheight | forecolor backcolor | language | removeformat'
  18813. },
  18814. tools: {
  18815. title: 'Tools',
  18816. items: 'spellchecker spellcheckerlanguage | a11ycheck code wordcount'
  18817. },
  18818. table: {
  18819. title: 'Table',
  18820. items: 'inserttable | cell row column | advtablesort | tableprops deletetable'
  18821. },
  18822. help: {
  18823. title: 'Help',
  18824. items: 'help'
  18825. }
  18826. };
  18827. const make = (menu, registry, editor) => {
  18828. const removedMenuItems = getRemovedMenuItems(editor).split(/[ ,]/);
  18829. return {
  18830. text: menu.title,
  18831. getItems: () => bind$3(menu.items, i => {
  18832. const itemName = i.toLowerCase();
  18833. if (itemName.trim().length === 0) {
  18834. return [];
  18835. } else if (exists(removedMenuItems, removedMenuItem => removedMenuItem === itemName)) {
  18836. return [];
  18837. } else if (itemName === 'separator' || itemName === '|') {
  18838. return [{ type: 'separator' }];
  18839. } else if (registry.menuItems[itemName]) {
  18840. return [registry.menuItems[itemName]];
  18841. } else {
  18842. return [];
  18843. }
  18844. })
  18845. };
  18846. };
  18847. const parseItemsString = items => {
  18848. if (typeof items === 'string') {
  18849. return items.split(' ');
  18850. }
  18851. return items;
  18852. };
  18853. const identifyMenus = (editor, registry) => {
  18854. const rawMenuData = {
  18855. ...defaultMenus,
  18856. ...registry.menus
  18857. };
  18858. const userDefinedMenus = keys(registry.menus).length > 0;
  18859. const menubar = registry.menubar === undefined || registry.menubar === true ? parseItemsString(defaultMenubar) : parseItemsString(registry.menubar === false ? '' : registry.menubar);
  18860. const validMenus = filter$2(menubar, menuName => {
  18861. const isDefaultMenu = has$2(defaultMenus, menuName);
  18862. if (userDefinedMenus) {
  18863. return isDefaultMenu || get$g(registry.menus, menuName).exists(menu => has$2(menu, 'items'));
  18864. } else {
  18865. return isDefaultMenu;
  18866. }
  18867. });
  18868. const menus = map$2(validMenus, menuName => {
  18869. const menuData = rawMenuData[menuName];
  18870. return make({
  18871. title: menuData.title,
  18872. items: parseItemsString(menuData.items)
  18873. }, registry, editor);
  18874. });
  18875. return filter$2(menus, menu => {
  18876. const isNotSeparator = item => item.type !== 'separator';
  18877. return menu.getItems().length > 0 && exists(menu.getItems(), isNotSeparator);
  18878. });
  18879. };
  18880. const fireSkinLoaded = editor => {
  18881. const done = () => {
  18882. editor._skinLoaded = true;
  18883. fireSkinLoaded$1(editor);
  18884. };
  18885. return () => {
  18886. if (editor.initialized) {
  18887. done();
  18888. } else {
  18889. editor.on('init', done);
  18890. }
  18891. };
  18892. };
  18893. const fireSkinLoadError = (editor, err) => () => fireSkinLoadError$1(editor, { message: err });
  18894. const loadStylesheet = (editor, stylesheetUrl, styleSheetLoader) => {
  18895. editor.on('remove', () => styleSheetLoader.unload(stylesheetUrl));
  18896. return styleSheetLoader.load(stylesheetUrl);
  18897. };
  18898. const loadUiSkins = (editor, skinUrl) => {
  18899. const skinUiCss = skinUrl + '/skin.min.css';
  18900. return loadStylesheet(editor, skinUiCss, editor.ui.styleSheetLoader);
  18901. };
  18902. const loadShadowDomUiSkins = (editor, skinUrl) => {
  18903. const isInShadowRoot$1 = isInShadowRoot(SugarElement.fromDom(editor.getElement()));
  18904. if (isInShadowRoot$1) {
  18905. const shadowDomSkinCss = skinUrl + '/skin.shadowdom.min.css';
  18906. return loadStylesheet(editor, shadowDomSkinCss, global$7.DOM.styleSheetLoader);
  18907. } else {
  18908. return Promise.resolve();
  18909. }
  18910. };
  18911. const loadSkin = (isInline, editor) => {
  18912. const skinUrl = getSkinUrl(editor);
  18913. if (skinUrl) {
  18914. editor.contentCSS.push(skinUrl + (isInline ? '/content.inline' : '/content') + '.min.css');
  18915. }
  18916. if (!isSkinDisabled(editor) && isString(skinUrl)) {
  18917. Promise.all([
  18918. loadUiSkins(editor, skinUrl),
  18919. loadShadowDomUiSkins(editor, skinUrl)
  18920. ]).then(fireSkinLoaded(editor), fireSkinLoadError(editor, 'Skin could not be loaded'));
  18921. } else {
  18922. fireSkinLoaded(editor)();
  18923. }
  18924. };
  18925. const iframe = curry(loadSkin, false);
  18926. const inline = curry(loadSkin, true);
  18927. const onSetupFormatToggle = (editor, name) => api => {
  18928. const boundCallback = unbindable();
  18929. const init = () => {
  18930. api.setActive(editor.formatter.match(name));
  18931. const binding = editor.formatter.formatChanged(name, api.setActive);
  18932. boundCallback.set(binding);
  18933. };
  18934. editor.initialized ? init() : editor.once('init', init);
  18935. return () => {
  18936. editor.off('init', init);
  18937. boundCallback.clear();
  18938. };
  18939. };
  18940. const onSetupEvent = (editor, event, f) => api => {
  18941. const handleEvent = () => f(api);
  18942. const init = () => {
  18943. f(api);
  18944. editor.on(event, handleEvent);
  18945. };
  18946. editor.initialized ? init() : editor.once('init', init);
  18947. return () => {
  18948. editor.off('init', init);
  18949. editor.off(event, handleEvent);
  18950. };
  18951. };
  18952. const onActionToggleFormat$1 = editor => rawItem => () => {
  18953. editor.undoManager.transact(() => {
  18954. editor.focus();
  18955. editor.execCommand('mceToggleFormat', false, rawItem.format);
  18956. });
  18957. };
  18958. const onActionExecCommand = (editor, command) => () => editor.execCommand(command);
  18959. const generateSelectItems = (_editor, backstage, spec) => {
  18960. const generateItem = (rawItem, response, invalid, value) => {
  18961. const translatedText = backstage.shared.providers.translate(rawItem.title);
  18962. if (rawItem.type === 'separator') {
  18963. return Optional.some({
  18964. type: 'separator',
  18965. text: translatedText
  18966. });
  18967. } else if (rawItem.type === 'submenu') {
  18968. const items = bind$3(rawItem.getStyleItems(), si => validate(si, response, value));
  18969. if (response === 0 && items.length <= 0) {
  18970. return Optional.none();
  18971. } else {
  18972. return Optional.some({
  18973. type: 'nestedmenuitem',
  18974. text: translatedText,
  18975. enabled: items.length > 0,
  18976. getSubmenuItems: () => bind$3(rawItem.getStyleItems(), si => validate(si, response, value))
  18977. });
  18978. }
  18979. } else {
  18980. return Optional.some({
  18981. type: 'togglemenuitem',
  18982. text: translatedText,
  18983. icon: rawItem.icon,
  18984. active: rawItem.isSelected(value),
  18985. enabled: !invalid,
  18986. onAction: spec.onAction(rawItem),
  18987. ...rawItem.getStylePreview().fold(() => ({}), preview => ({ meta: { style: preview } }))
  18988. });
  18989. }
  18990. };
  18991. const validate = (item, response, value) => {
  18992. const invalid = item.type === 'formatter' && spec.isInvalid(item);
  18993. if (response === 0) {
  18994. return invalid ? [] : generateItem(item, response, false, value).toArray();
  18995. } else {
  18996. return generateItem(item, response, invalid, value).toArray();
  18997. }
  18998. };
  18999. const validateItems = preItems => {
  19000. const value = spec.getCurrentValue();
  19001. const response = spec.shouldHide ? 0 : 1;
  19002. return bind$3(preItems, item => validate(item, response, value));
  19003. };
  19004. const getFetch = (backstage, getStyleItems) => (comp, callback) => {
  19005. const preItems = getStyleItems();
  19006. const items = validateItems(preItems);
  19007. const menu = build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false);
  19008. callback(menu);
  19009. };
  19010. return {
  19011. validateItems,
  19012. getFetch
  19013. };
  19014. };
  19015. const createMenuItems = (editor, backstage, spec) => {
  19016. const dataset = spec.dataset;
  19017. const getStyleItems = dataset.type === 'basic' ? () => map$2(dataset.data, d => processBasic(d, spec.isSelectedFor, spec.getPreviewFor)) : dataset.getData;
  19018. return {
  19019. items: generateSelectItems(editor, backstage, spec),
  19020. getStyleItems
  19021. };
  19022. };
  19023. const createSelectButton = (editor, backstage, spec) => {
  19024. const {items, getStyleItems} = createMenuItems(editor, backstage, spec);
  19025. const getApi = comp => ({ getComponent: constant$1(comp) });
  19026. const onSetup = onSetupEvent(editor, 'NodeChange', api => {
  19027. const comp = api.getComponent();
  19028. spec.updateText(comp);
  19029. });
  19030. return renderCommonDropdown({
  19031. text: spec.icon.isSome() ? Optional.none() : spec.text,
  19032. icon: spec.icon,
  19033. tooltip: Optional.from(spec.tooltip),
  19034. role: Optional.none(),
  19035. fetch: items.getFetch(backstage, getStyleItems),
  19036. onSetup,
  19037. getApi,
  19038. columns: 1,
  19039. presets: 'normal',
  19040. classes: spec.icon.isSome() ? [] : ['bespoke'],
  19041. dropdownBehaviours: []
  19042. }, 'tox-tbtn', backstage.shared);
  19043. };
  19044. const process = rawFormats => map$2(rawFormats, item => {
  19045. let title = item, format = item;
  19046. const values = item.split('=');
  19047. if (values.length > 1) {
  19048. title = values[0];
  19049. format = values[1];
  19050. }
  19051. return {
  19052. title,
  19053. format
  19054. };
  19055. });
  19056. const buildBasicStaticDataset = data => ({
  19057. type: 'basic',
  19058. data
  19059. });
  19060. var Delimiter;
  19061. (function (Delimiter) {
  19062. Delimiter[Delimiter['SemiColon'] = 0] = 'SemiColon';
  19063. Delimiter[Delimiter['Space'] = 1] = 'Space';
  19064. }(Delimiter || (Delimiter = {})));
  19065. const split = (rawFormats, delimiter) => {
  19066. if (delimiter === Delimiter.SemiColon) {
  19067. return rawFormats.replace(/;$/, '').split(';');
  19068. } else {
  19069. return rawFormats.split(' ');
  19070. }
  19071. };
  19072. const buildBasicSettingsDataset = (editor, settingName, delimiter) => {
  19073. const rawFormats = editor.options.get(settingName);
  19074. const data = process(split(rawFormats, delimiter));
  19075. return {
  19076. type: 'basic',
  19077. data
  19078. };
  19079. };
  19080. const alignMenuItems = [
  19081. {
  19082. title: 'Left',
  19083. icon: 'align-left',
  19084. format: 'alignleft',
  19085. command: 'JustifyLeft'
  19086. },
  19087. {
  19088. title: 'Center',
  19089. icon: 'align-center',
  19090. format: 'aligncenter',
  19091. command: 'JustifyCenter'
  19092. },
  19093. {
  19094. title: 'Right',
  19095. icon: 'align-right',
  19096. format: 'alignright',
  19097. command: 'JustifyRight'
  19098. },
  19099. {
  19100. title: 'Justify',
  19101. icon: 'align-justify',
  19102. format: 'alignjustify',
  19103. command: 'JustifyFull'
  19104. }
  19105. ];
  19106. const getSpec$4 = editor => {
  19107. const getMatchingValue = () => find$5(alignMenuItems, item => editor.formatter.match(item.format));
  19108. const isSelectedFor = format => () => editor.formatter.match(format);
  19109. const getPreviewFor = _format => Optional.none;
  19110. const updateSelectMenuIcon = comp => {
  19111. const match = getMatchingValue();
  19112. const alignment = match.fold(constant$1('left'), item => item.title.toLowerCase());
  19113. emitWith(comp, updateMenuIcon, { icon: `align-${ alignment }` });
  19114. };
  19115. const dataset = buildBasicStaticDataset(alignMenuItems);
  19116. const onAction = rawItem => () => find$5(alignMenuItems, item => item.format === rawItem.format).each(item => editor.execCommand(item.command));
  19117. return {
  19118. tooltip: 'Align',
  19119. text: Optional.none(),
  19120. icon: Optional.some('align-left'),
  19121. isSelectedFor,
  19122. getCurrentValue: Optional.none,
  19123. getPreviewFor,
  19124. onAction,
  19125. updateText: updateSelectMenuIcon,
  19126. dataset,
  19127. shouldHide: false,
  19128. isInvalid: item => !editor.formatter.canApply(item.format)
  19129. };
  19130. };
  19131. const createAlignButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$4(editor));
  19132. const createAlignMenu = (editor, backstage) => {
  19133. const menuItems = createMenuItems(editor, backstage, getSpec$4(editor));
  19134. editor.ui.registry.addNestedMenuItem('align', {
  19135. text: backstage.shared.providers.translate('Align'),
  19136. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  19137. });
  19138. };
  19139. const findNearest = (editor, getStyles) => {
  19140. const styles = getStyles();
  19141. const formats = map$2(styles, style => style.format);
  19142. return Optional.from(editor.formatter.closest(formats)).bind(fmt => find$5(styles, data => data.format === fmt)).orThunk(() => someIf(editor.formatter.match('p'), {
  19143. title: 'Paragraph',
  19144. format: 'p'
  19145. }));
  19146. };
  19147. const getSpec$3 = editor => {
  19148. const fallbackFormat = 'Paragraph';
  19149. const isSelectedFor = format => () => editor.formatter.match(format);
  19150. const getPreviewFor = format => () => {
  19151. const fmt = editor.formatter.get(format);
  19152. return Optional.some({
  19153. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  19154. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  19155. });
  19156. };
  19157. const updateSelectMenuText = comp => {
  19158. const detectedFormat = findNearest(editor, () => dataset.data);
  19159. const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
  19160. emitWith(comp, updateMenuText, { text });
  19161. };
  19162. const dataset = buildBasicSettingsDataset(editor, 'block_formats', Delimiter.SemiColon);
  19163. return {
  19164. tooltip: 'Blocks',
  19165. text: Optional.some(fallbackFormat),
  19166. icon: Optional.none(),
  19167. isSelectedFor,
  19168. getCurrentValue: Optional.none,
  19169. getPreviewFor,
  19170. onAction: onActionToggleFormat$1(editor),
  19171. updateText: updateSelectMenuText,
  19172. dataset,
  19173. shouldHide: false,
  19174. isInvalid: item => !editor.formatter.canApply(item.format)
  19175. };
  19176. };
  19177. const createBlocksButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$3(editor));
  19178. const createBlocksMenu = (editor, backstage) => {
  19179. const menuItems = createMenuItems(editor, backstage, getSpec$3(editor));
  19180. editor.ui.registry.addNestedMenuItem('blocks', {
  19181. text: 'Blocks',
  19182. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  19183. });
  19184. };
  19185. const systemStackFonts = [
  19186. '-apple-system',
  19187. 'Segoe UI',
  19188. 'Roboto',
  19189. 'Helvetica Neue',
  19190. 'sans-serif'
  19191. ];
  19192. const splitFonts = fontFamily => {
  19193. const fonts = fontFamily.split(/\s*,\s*/);
  19194. return map$2(fonts, font => font.replace(/^['"]+|['"]+$/g, ''));
  19195. };
  19196. const isSystemFontStack = fontFamily => {
  19197. const matchesSystemStack = () => {
  19198. const fonts = splitFonts(fontFamily.toLowerCase());
  19199. return forall(systemStackFonts, font => fonts.indexOf(font.toLowerCase()) > -1);
  19200. };
  19201. return fontFamily.indexOf('-apple-system') === 0 && matchesSystemStack();
  19202. };
  19203. const getSpec$2 = editor => {
  19204. const systemFont = 'System Font';
  19205. const getMatchingValue = () => {
  19206. const getFirstFont = fontFamily => fontFamily ? splitFonts(fontFamily)[0] : '';
  19207. const fontFamily = editor.queryCommandValue('FontName');
  19208. const items = dataset.data;
  19209. const font = fontFamily ? fontFamily.toLowerCase() : '';
  19210. const matchOpt = find$5(items, item => {
  19211. const format = item.format;
  19212. return format.toLowerCase() === font || getFirstFont(format).toLowerCase() === getFirstFont(font).toLowerCase();
  19213. }).orThunk(() => {
  19214. return someIf(isSystemFontStack(font), {
  19215. title: systemFont,
  19216. format: font
  19217. });
  19218. });
  19219. return {
  19220. matchOpt,
  19221. font: fontFamily
  19222. };
  19223. };
  19224. const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
  19225. const getCurrentValue = () => {
  19226. const {matchOpt} = getMatchingValue();
  19227. return matchOpt;
  19228. };
  19229. const getPreviewFor = item => () => Optional.some({
  19230. tag: 'div',
  19231. styles: item.indexOf('dings') === -1 ? { 'font-family': item } : {}
  19232. });
  19233. const onAction = rawItem => () => {
  19234. editor.undoManager.transact(() => {
  19235. editor.focus();
  19236. editor.execCommand('FontName', false, rawItem.format);
  19237. });
  19238. };
  19239. const updateSelectMenuText = comp => {
  19240. const {matchOpt, font} = getMatchingValue();
  19241. const text = matchOpt.fold(constant$1(font), item => item.title);
  19242. emitWith(comp, updateMenuText, { text });
  19243. };
  19244. const dataset = buildBasicSettingsDataset(editor, 'font_family_formats', Delimiter.SemiColon);
  19245. return {
  19246. tooltip: 'Fonts',
  19247. text: Optional.some(systemFont),
  19248. icon: Optional.none(),
  19249. isSelectedFor,
  19250. getCurrentValue,
  19251. getPreviewFor,
  19252. onAction,
  19253. updateText: updateSelectMenuText,
  19254. dataset,
  19255. shouldHide: false,
  19256. isInvalid: never
  19257. };
  19258. };
  19259. const createFontFamilyButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$2(editor));
  19260. const createFontFamilyMenu = (editor, backstage) => {
  19261. const menuItems = createMenuItems(editor, backstage, getSpec$2(editor));
  19262. editor.ui.registry.addNestedMenuItem('fontfamily', {
  19263. text: backstage.shared.providers.translate('Fonts'),
  19264. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  19265. });
  19266. };
  19267. const legacyFontSizes = {
  19268. '8pt': '1',
  19269. '10pt': '2',
  19270. '12pt': '3',
  19271. '14pt': '4',
  19272. '18pt': '5',
  19273. '24pt': '6',
  19274. '36pt': '7'
  19275. };
  19276. const keywordFontSizes = {
  19277. 'xx-small': '7pt',
  19278. 'x-small': '8pt',
  19279. 'small': '10pt',
  19280. 'medium': '12pt',
  19281. 'large': '14pt',
  19282. 'x-large': '18pt',
  19283. 'xx-large': '24pt'
  19284. };
  19285. const round = (number, precision) => {
  19286. const factor = Math.pow(10, precision);
  19287. return Math.round(number * factor) / factor;
  19288. };
  19289. const toPt = (fontSize, precision) => {
  19290. if (/[0-9.]+px$/.test(fontSize)) {
  19291. return round(parseInt(fontSize, 10) * 72 / 96, precision || 0) + 'pt';
  19292. } else {
  19293. return get$g(keywordFontSizes, fontSize).getOr(fontSize);
  19294. }
  19295. };
  19296. const toLegacy = fontSize => get$g(legacyFontSizes, fontSize).getOr('');
  19297. const getSpec$1 = editor => {
  19298. const getMatchingValue = () => {
  19299. let matchOpt = Optional.none();
  19300. const items = dataset.data;
  19301. const fontSize = editor.queryCommandValue('FontSize');
  19302. if (fontSize) {
  19303. for (let precision = 3; matchOpt.isNone() && precision >= 0; precision--) {
  19304. const pt = toPt(fontSize, precision);
  19305. const legacy = toLegacy(pt);
  19306. matchOpt = find$5(items, item => item.format === fontSize || item.format === pt || item.format === legacy);
  19307. }
  19308. }
  19309. return {
  19310. matchOpt,
  19311. size: fontSize
  19312. };
  19313. };
  19314. const isSelectedFor = item => valueOpt => valueOpt.exists(value => value.format === item);
  19315. const getCurrentValue = () => {
  19316. const {matchOpt} = getMatchingValue();
  19317. return matchOpt;
  19318. };
  19319. const getPreviewFor = constant$1(Optional.none);
  19320. const onAction = rawItem => () => {
  19321. editor.undoManager.transact(() => {
  19322. editor.focus();
  19323. editor.execCommand('FontSize', false, rawItem.format);
  19324. });
  19325. };
  19326. const updateSelectMenuText = comp => {
  19327. const {matchOpt, size} = getMatchingValue();
  19328. const text = matchOpt.fold(constant$1(size), match => match.title);
  19329. emitWith(comp, updateMenuText, { text });
  19330. };
  19331. const dataset = buildBasicSettingsDataset(editor, 'font_size_formats', Delimiter.Space);
  19332. return {
  19333. tooltip: 'Font sizes',
  19334. text: Optional.some('12pt'),
  19335. icon: Optional.none(),
  19336. isSelectedFor,
  19337. getPreviewFor,
  19338. getCurrentValue,
  19339. onAction,
  19340. updateText: updateSelectMenuText,
  19341. dataset,
  19342. shouldHide: false,
  19343. isInvalid: never
  19344. };
  19345. };
  19346. const createFontSizeButton = (editor, backstage) => createSelectButton(editor, backstage, getSpec$1(editor));
  19347. const createFontSizeMenu = (editor, backstage) => {
  19348. const menuItems = createMenuItems(editor, backstage, getSpec$1(editor));
  19349. editor.ui.registry.addNestedMenuItem('fontsize', {
  19350. text: 'Font sizes',
  19351. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  19352. });
  19353. };
  19354. const getSpec = (editor, dataset) => {
  19355. const fallbackFormat = 'Paragraph';
  19356. const isSelectedFor = format => () => editor.formatter.match(format);
  19357. const getPreviewFor = format => () => {
  19358. const fmt = editor.formatter.get(format);
  19359. return fmt !== undefined ? Optional.some({
  19360. tag: fmt.length > 0 ? fmt[0].inline || fmt[0].block || 'div' : 'div',
  19361. styles: editor.dom.parseStyle(editor.formatter.getCssText(format))
  19362. }) : Optional.none();
  19363. };
  19364. const updateSelectMenuText = comp => {
  19365. const getFormatItems = fmt => {
  19366. const subs = fmt.items;
  19367. return subs !== undefined && subs.length > 0 ? bind$3(subs, getFormatItems) : [{
  19368. title: fmt.title,
  19369. format: fmt.format
  19370. }];
  19371. };
  19372. const flattenedItems = bind$3(getStyleFormats(editor), getFormatItems);
  19373. const detectedFormat = findNearest(editor, constant$1(flattenedItems));
  19374. const text = detectedFormat.fold(constant$1(fallbackFormat), fmt => fmt.title);
  19375. emitWith(comp, updateMenuText, { text });
  19376. };
  19377. return {
  19378. tooltip: 'Formats',
  19379. text: Optional.some(fallbackFormat),
  19380. icon: Optional.none(),
  19381. isSelectedFor,
  19382. getCurrentValue: Optional.none,
  19383. getPreviewFor,
  19384. onAction: onActionToggleFormat$1(editor),
  19385. updateText: updateSelectMenuText,
  19386. shouldHide: shouldAutoHideStyleFormats(editor),
  19387. isInvalid: item => !editor.formatter.canApply(item.format),
  19388. dataset
  19389. };
  19390. };
  19391. const createStylesButton = (editor, backstage) => {
  19392. const dataset = {
  19393. type: 'advanced',
  19394. ...backstage.styles
  19395. };
  19396. return createSelectButton(editor, backstage, getSpec(editor, dataset));
  19397. };
  19398. const createStylesMenu = (editor, backstage) => {
  19399. const dataset = {
  19400. type: 'advanced',
  19401. ...backstage.styles
  19402. };
  19403. const menuItems = createMenuItems(editor, backstage, getSpec(editor, dataset));
  19404. editor.ui.registry.addNestedMenuItem('styles', {
  19405. text: 'Formats',
  19406. getSubmenuItems: () => menuItems.items.validateItems(menuItems.getStyleItems())
  19407. });
  19408. };
  19409. const events$3 = (reflectingConfig, reflectingState) => {
  19410. const update = (component, data) => {
  19411. reflectingConfig.updateState.each(updateState => {
  19412. const newState = updateState(component, data);
  19413. reflectingState.set(newState);
  19414. });
  19415. reflectingConfig.renderComponents.each(renderComponents => {
  19416. const newComponents = renderComponents(data, reflectingState.get());
  19417. const replacer = reflectingConfig.reuseDom ? withReuse : withoutReuse;
  19418. replacer(component, newComponents);
  19419. });
  19420. };
  19421. return derive$2([
  19422. run$1(receive(), (component, message) => {
  19423. const receivingData = message;
  19424. if (!receivingData.universal) {
  19425. const channel = reflectingConfig.channel;
  19426. if (contains$2(receivingData.channels, channel)) {
  19427. update(component, receivingData.data);
  19428. }
  19429. }
  19430. }),
  19431. runOnAttached((comp, _se) => {
  19432. reflectingConfig.initialData.each(rawData => {
  19433. update(comp, rawData);
  19434. });
  19435. })
  19436. ]);
  19437. };
  19438. var ActiveReflecting = /*#__PURE__*/Object.freeze({
  19439. __proto__: null,
  19440. events: events$3
  19441. });
  19442. const getState = (component, replaceConfig, reflectState) => reflectState;
  19443. var ReflectingApis = /*#__PURE__*/Object.freeze({
  19444. __proto__: null,
  19445. getState: getState
  19446. });
  19447. var ReflectingSchema = [
  19448. required$1('channel'),
  19449. option$3('renderComponents'),
  19450. option$3('updateState'),
  19451. option$3('initialData'),
  19452. defaultedBoolean('reuseDom', true)
  19453. ];
  19454. const init$3 = () => {
  19455. const cell = Cell(Optional.none());
  19456. const clear = () => cell.set(Optional.none());
  19457. const readState = () => cell.get().getOr('none');
  19458. return {
  19459. readState,
  19460. get: cell.get,
  19461. set: cell.set,
  19462. clear
  19463. };
  19464. };
  19465. var ReflectingState = /*#__PURE__*/Object.freeze({
  19466. __proto__: null,
  19467. init: init$3
  19468. });
  19469. const Reflecting = create$3({
  19470. fields: ReflectingSchema,
  19471. name: 'reflecting',
  19472. active: ActiveReflecting,
  19473. apis: ReflectingApis,
  19474. state: ReflectingState
  19475. });
  19476. const schema$7 = constant$1([
  19477. required$1('toggleClass'),
  19478. required$1('fetch'),
  19479. onStrictHandler('onExecute'),
  19480. defaulted('getHotspot', Optional.some),
  19481. defaulted('getAnchorOverrides', constant$1({})),
  19482. schema$y(),
  19483. onStrictHandler('onItemExecute'),
  19484. option$3('lazySink'),
  19485. required$1('dom'),
  19486. onHandler('onOpen'),
  19487. field('splitDropdownBehaviours', [
  19488. Coupling,
  19489. Keying,
  19490. Focusing
  19491. ]),
  19492. defaulted('matchWidth', false),
  19493. defaulted('useMinWidth', false),
  19494. defaulted('eventOrder', {}),
  19495. option$3('role')
  19496. ].concat(sandboxFields()));
  19497. const arrowPart = required({
  19498. factory: Button,
  19499. schema: [required$1('dom')],
  19500. name: 'arrow',
  19501. defaults: () => {
  19502. return { buttonBehaviours: derive$1([Focusing.revoke()]) };
  19503. },
  19504. overrides: detail => {
  19505. return {
  19506. dom: {
  19507. tag: 'span',
  19508. attributes: { role: 'presentation' }
  19509. },
  19510. action: arrow => {
  19511. arrow.getSystem().getByUid(detail.uid).each(emitExecute);
  19512. },
  19513. buttonBehaviours: derive$1([Toggling.config({
  19514. toggleOnExecute: false,
  19515. toggleClass: detail.toggleClass
  19516. })])
  19517. };
  19518. }
  19519. });
  19520. const buttonPart = required({
  19521. factory: Button,
  19522. schema: [required$1('dom')],
  19523. name: 'button',
  19524. defaults: () => {
  19525. return { buttonBehaviours: derive$1([Focusing.revoke()]) };
  19526. },
  19527. overrides: detail => {
  19528. return {
  19529. dom: {
  19530. tag: 'span',
  19531. attributes: { role: 'presentation' }
  19532. },
  19533. action: btn => {
  19534. btn.getSystem().getByUid(detail.uid).each(splitDropdown => {
  19535. detail.onExecute(splitDropdown, btn);
  19536. });
  19537. }
  19538. };
  19539. }
  19540. });
  19541. const parts$3 = constant$1([
  19542. arrowPart,
  19543. buttonPart,
  19544. optional({
  19545. factory: {
  19546. sketch: spec => {
  19547. return {
  19548. uid: spec.uid,
  19549. dom: {
  19550. tag: 'span',
  19551. styles: { display: 'none' },
  19552. attributes: { 'aria-hidden': 'true' },
  19553. innerHtml: spec.text
  19554. }
  19555. };
  19556. }
  19557. },
  19558. schema: [required$1('text')],
  19559. name: 'aria-descriptor'
  19560. }),
  19561. external({
  19562. schema: [tieredMenuMarkers()],
  19563. name: 'menu',
  19564. defaults: detail => {
  19565. return {
  19566. onExecute: (tmenu, item) => {
  19567. tmenu.getSystem().getByUid(detail.uid).each(splitDropdown => {
  19568. detail.onItemExecute(splitDropdown, tmenu, item);
  19569. });
  19570. }
  19571. };
  19572. }
  19573. }),
  19574. partType$1()
  19575. ]);
  19576. const factory$5 = (detail, components, spec, externals) => {
  19577. const switchToMenu = sandbox => {
  19578. Composing.getCurrent(sandbox).each(current => {
  19579. Highlighting.highlightFirst(current);
  19580. Keying.focusIn(current);
  19581. });
  19582. };
  19583. const action = component => {
  19584. const onOpenSync = switchToMenu;
  19585. togglePopup(detail, identity, component, externals, onOpenSync, HighlightOnOpen.HighlightFirst).get(noop);
  19586. };
  19587. const openMenu = comp => {
  19588. action(comp);
  19589. return Optional.some(true);
  19590. };
  19591. const executeOnButton = comp => {
  19592. const button = getPartOrDie(comp, detail, 'button');
  19593. emitExecute(button);
  19594. return Optional.some(true);
  19595. };
  19596. const buttonEvents = {
  19597. ...derive$2([runOnAttached((component, _simulatedEvent) => {
  19598. const ariaDescriptor = getPart(component, detail, 'aria-descriptor');
  19599. ariaDescriptor.each(descriptor => {
  19600. const descriptorId = generate$6('aria');
  19601. set$9(descriptor.element, 'id', descriptorId);
  19602. set$9(component.element, 'aria-describedby', descriptorId);
  19603. });
  19604. })]),
  19605. ...events$a(Optional.some(action))
  19606. };
  19607. const apis = {
  19608. repositionMenus: comp => {
  19609. if (Toggling.isOn(comp)) {
  19610. repositionMenus(comp);
  19611. }
  19612. }
  19613. };
  19614. return {
  19615. uid: detail.uid,
  19616. dom: detail.dom,
  19617. components,
  19618. apis,
  19619. eventOrder: {
  19620. ...detail.eventOrder,
  19621. [execute$5()]: [
  19622. 'disabling',
  19623. 'toggling',
  19624. 'alloy.base.behaviour'
  19625. ]
  19626. },
  19627. events: buttonEvents,
  19628. behaviours: augment(detail.splitDropdownBehaviours, [
  19629. Coupling.config({
  19630. others: {
  19631. sandbox: hotspot => {
  19632. const arrow = getPartOrDie(hotspot, detail, 'arrow');
  19633. const extras = {
  19634. onOpen: () => {
  19635. Toggling.on(arrow);
  19636. Toggling.on(hotspot);
  19637. },
  19638. onClose: () => {
  19639. Toggling.off(arrow);
  19640. Toggling.off(hotspot);
  19641. }
  19642. };
  19643. return makeSandbox$1(detail, hotspot, extras);
  19644. }
  19645. }
  19646. }),
  19647. Keying.config({
  19648. mode: 'special',
  19649. onSpace: executeOnButton,
  19650. onEnter: executeOnButton,
  19651. onDown: openMenu
  19652. }),
  19653. Focusing.config({}),
  19654. Toggling.config({
  19655. toggleOnExecute: false,
  19656. aria: { mode: 'expanded' }
  19657. })
  19658. ]),
  19659. domModification: {
  19660. attributes: {
  19661. 'role': detail.role.getOr('button'),
  19662. 'aria-haspopup': true
  19663. }
  19664. }
  19665. };
  19666. };
  19667. const SplitDropdown = composite({
  19668. name: 'SplitDropdown',
  19669. configFields: schema$7(),
  19670. partFields: parts$3(),
  19671. factory: factory$5,
  19672. apis: { repositionMenus: (apis, comp) => apis.repositionMenus(comp) }
  19673. });
  19674. const getButtonApi = component => ({
  19675. isEnabled: () => !Disabling.isDisabled(component),
  19676. setEnabled: state => Disabling.set(component, !state)
  19677. });
  19678. const getToggleApi = component => ({
  19679. setActive: state => {
  19680. Toggling.set(component, state);
  19681. },
  19682. isActive: () => Toggling.isOn(component),
  19683. isEnabled: () => !Disabling.isDisabled(component),
  19684. setEnabled: state => Disabling.set(component, !state)
  19685. });
  19686. const getTooltipAttributes = (tooltip, providersBackstage) => tooltip.map(tooltip => ({
  19687. 'aria-label': providersBackstage.translate(tooltip),
  19688. 'title': providersBackstage.translate(tooltip)
  19689. })).getOr({});
  19690. const focusButtonEvent = generate$6('focus-button');
  19691. const renderCommonStructure = (icon, text, tooltip, receiver, behaviours, providersBackstage) => {
  19692. return {
  19693. dom: {
  19694. tag: 'button',
  19695. classes: ['tox-tbtn'].concat(text.isSome() ? ['tox-tbtn--select'] : []),
  19696. attributes: getTooltipAttributes(tooltip, providersBackstage)
  19697. },
  19698. components: componentRenderPipeline([
  19699. icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons)),
  19700. text.map(text => renderLabel(text, 'tox-tbtn', providersBackstage))
  19701. ]),
  19702. eventOrder: {
  19703. [mousedown()]: [
  19704. 'focusing',
  19705. 'alloy.base.behaviour',
  19706. 'common-button-display-events'
  19707. ]
  19708. },
  19709. buttonBehaviours: derive$1([
  19710. DisablingConfigs.toolbarButton(providersBackstage.isDisabled),
  19711. receivingConfig(),
  19712. config('common-button-display-events', [run$1(mousedown(), (button, se) => {
  19713. se.event.prevent();
  19714. emit(button, focusButtonEvent);
  19715. })])
  19716. ].concat(receiver.map(r => Reflecting.config({
  19717. channel: r,
  19718. initialData: {
  19719. icon,
  19720. text
  19721. },
  19722. renderComponents: (data, _state) => componentRenderPipeline([
  19723. data.icon.map(iconName => renderIconFromPack(iconName, providersBackstage.icons)),
  19724. data.text.map(text => renderLabel(text, 'tox-tbtn', providersBackstage))
  19725. ])
  19726. })).toArray()).concat(behaviours.getOr([])))
  19727. };
  19728. };
  19729. const renderFloatingToolbarButton = (spec, backstage, identifyButtons, attributes) => {
  19730. const sharedBackstage = backstage.shared;
  19731. return FloatingToolbarButton.sketch({
  19732. lazySink: sharedBackstage.getSink,
  19733. fetch: () => Future.nu(resolve => {
  19734. resolve(map$2(identifyButtons(spec.items), renderToolbarGroup));
  19735. }),
  19736. markers: { toggledClass: 'tox-tbtn--enabled' },
  19737. parts: {
  19738. button: renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), sharedBackstage.providers),
  19739. toolbar: {
  19740. dom: {
  19741. tag: 'div',
  19742. classes: ['tox-toolbar__overflow'],
  19743. attributes
  19744. }
  19745. }
  19746. }
  19747. });
  19748. };
  19749. const renderCommonToolbarButton = (spec, specialisation, providersBackstage) => {
  19750. const editorOffCell = Cell(noop);
  19751. const structure = renderCommonStructure(spec.icon, spec.text, spec.tooltip, Optional.none(), Optional.none(), providersBackstage);
  19752. return Button.sketch({
  19753. dom: structure.dom,
  19754. components: structure.components,
  19755. eventOrder: toolbarButtonEventOrder,
  19756. buttonBehaviours: derive$1([
  19757. config('toolbar-button-events', [
  19758. onToolbarButtonExecute({
  19759. onAction: spec.onAction,
  19760. getApi: specialisation.getApi
  19761. }),
  19762. onControlAttached(specialisation, editorOffCell),
  19763. onControlDetached(specialisation, editorOffCell)
  19764. ]),
  19765. DisablingConfigs.toolbarButton(() => !spec.enabled || providersBackstage.isDisabled()),
  19766. receivingConfig()
  19767. ].concat(specialisation.toolbarButtonBehaviours))
  19768. });
  19769. };
  19770. const renderToolbarButton = (spec, providersBackstage) => renderToolbarButtonWith(spec, providersBackstage, []);
  19771. const renderToolbarButtonWith = (spec, providersBackstage, bonusEvents) => renderCommonToolbarButton(spec, {
  19772. toolbarButtonBehaviours: [].concat(bonusEvents.length > 0 ? [config('toolbarButtonWith', bonusEvents)] : []),
  19773. getApi: getButtonApi,
  19774. onSetup: spec.onSetup
  19775. }, providersBackstage);
  19776. const renderToolbarToggleButton = (spec, providersBackstage) => renderToolbarToggleButtonWith(spec, providersBackstage, []);
  19777. const renderToolbarToggleButtonWith = (spec, providersBackstage, bonusEvents) => deepMerge(renderCommonToolbarButton(spec, {
  19778. toolbarButtonBehaviours: [
  19779. Replacing.config({}),
  19780. Toggling.config({
  19781. toggleClass: 'tox-tbtn--enabled',
  19782. aria: { mode: 'pressed' },
  19783. toggleOnExecute: false
  19784. })
  19785. ].concat(bonusEvents.length > 0 ? [config('toolbarToggleButtonWith', bonusEvents)] : []),
  19786. getApi: getToggleApi,
  19787. onSetup: spec.onSetup
  19788. }, providersBackstage));
  19789. 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 => {
  19790. spec.onItemAction(getApi(comp), value);
  19791. }, spec.columns, spec.presets, ItemResponse$1.CLOSE_ON_EXECUTE, spec.select.getOr(never), providersBackstage), {
  19792. movement: deriveMenuMovement(spec.columns, spec.presets),
  19793. menuBehaviours: SimpleBehaviours.unnamedEvents(spec.columns !== 'auto' ? [] : [runOnAttached((comp, _se) => {
  19794. detectSize(comp, 4, classForPreset(spec.presets)).each(({numRows, numColumns}) => {
  19795. Keying.setGridSize(comp, numRows, numColumns);
  19796. });
  19797. })])
  19798. }))));
  19799. const renderSplitButton = (spec, sharedBackstage) => {
  19800. const displayChannel = generate$6('channel-update-split-dropdown-display');
  19801. const getApi = comp => ({
  19802. isEnabled: () => !Disabling.isDisabled(comp),
  19803. setEnabled: state => Disabling.set(comp, !state),
  19804. setIconFill: (id, value) => {
  19805. descendant(comp.element, 'svg path[id="' + id + '"], rect[id="' + id + '"]').each(underlinePath => {
  19806. set$9(underlinePath, 'fill', value);
  19807. });
  19808. },
  19809. setActive: state => {
  19810. set$9(comp.element, 'aria-pressed', state);
  19811. descendant(comp.element, 'span').each(button => {
  19812. comp.getSystem().getByDom(button).each(buttonComp => Toggling.set(buttonComp, state));
  19813. });
  19814. },
  19815. isActive: () => descendant(comp.element, 'span').exists(button => comp.getSystem().getByDom(button).exists(Toggling.isOn))
  19816. });
  19817. const editorOffCell = Cell(noop);
  19818. const specialisation = {
  19819. getApi,
  19820. onSetup: spec.onSetup
  19821. };
  19822. return SplitDropdown.sketch({
  19823. dom: {
  19824. tag: 'div',
  19825. classes: ['tox-split-button'],
  19826. attributes: {
  19827. 'aria-pressed': false,
  19828. ...getTooltipAttributes(spec.tooltip, sharedBackstage.providers)
  19829. }
  19830. },
  19831. onExecute: button => {
  19832. spec.onAction(getApi(button));
  19833. },
  19834. onItemExecute: (_a, _b, _c) => {
  19835. },
  19836. splitDropdownBehaviours: derive$1([
  19837. DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
  19838. receivingConfig(),
  19839. config('split-dropdown-events', [
  19840. run$1(focusButtonEvent, Focusing.focus),
  19841. onControlAttached(specialisation, editorOffCell),
  19842. onControlDetached(specialisation, editorOffCell)
  19843. ]),
  19844. Unselecting.config({})
  19845. ]),
  19846. eventOrder: {
  19847. [attachedToDom()]: [
  19848. 'alloy.base.behaviour',
  19849. 'split-dropdown-events'
  19850. ]
  19851. },
  19852. toggleClass: 'tox-tbtn--enabled',
  19853. lazySink: sharedBackstage.getSink,
  19854. fetch: fetchChoices(getApi, spec, sharedBackstage.providers),
  19855. parts: { menu: part(false, spec.columns, spec.presets) },
  19856. components: [
  19857. SplitDropdown.parts.button(renderCommonStructure(spec.icon, spec.text, Optional.none(), Optional.some(displayChannel), Optional.some([Toggling.config({
  19858. toggleClass: 'tox-tbtn--enabled',
  19859. toggleOnExecute: false
  19860. })]), sharedBackstage.providers)),
  19861. SplitDropdown.parts.arrow({
  19862. dom: {
  19863. tag: 'button',
  19864. classes: [
  19865. 'tox-tbtn',
  19866. 'tox-split-button__chevron'
  19867. ],
  19868. innerHtml: get$2('chevron-down', sharedBackstage.providers.icons)
  19869. },
  19870. buttonBehaviours: derive$1([
  19871. DisablingConfigs.splitButton(sharedBackstage.providers.isDisabled),
  19872. receivingConfig(),
  19873. addFocusableBehaviour()
  19874. ])
  19875. }),
  19876. SplitDropdown.parts['aria-descriptor']({ text: sharedBackstage.providers.translate('To open the popup, press Shift+Enter') })
  19877. ]
  19878. });
  19879. };
  19880. const defaultToolbar = [
  19881. {
  19882. name: 'history',
  19883. items: [
  19884. 'undo',
  19885. 'redo'
  19886. ]
  19887. },
  19888. {
  19889. name: 'styles',
  19890. items: ['styles']
  19891. },
  19892. {
  19893. name: 'formatting',
  19894. items: [
  19895. 'bold',
  19896. 'italic'
  19897. ]
  19898. },
  19899. {
  19900. name: 'alignment',
  19901. items: [
  19902. 'alignleft',
  19903. 'aligncenter',
  19904. 'alignright',
  19905. 'alignjustify'
  19906. ]
  19907. },
  19908. {
  19909. name: 'indentation',
  19910. items: [
  19911. 'outdent',
  19912. 'indent'
  19913. ]
  19914. },
  19915. {
  19916. name: 'permanent pen',
  19917. items: ['permanentpen']
  19918. },
  19919. {
  19920. name: 'comments',
  19921. items: ['addcomment']
  19922. }
  19923. ];
  19924. const renderFromBridge = (bridgeBuilder, render) => (spec, extras, editor) => {
  19925. const internal = bridgeBuilder(spec).mapError(errInfo => formatError(errInfo)).getOrDie();
  19926. return render(internal, extras, editor);
  19927. };
  19928. const types = {
  19929. button: renderFromBridge(createToolbarButton, (s, extras) => renderToolbarButton(s, extras.backstage.shared.providers)),
  19930. togglebutton: renderFromBridge(createToggleButton, (s, extras) => renderToolbarToggleButton(s, extras.backstage.shared.providers)),
  19931. menubutton: renderFromBridge(createMenuButton, (s, extras) => renderMenuButton(s, 'tox-tbtn', extras.backstage, Optional.none())),
  19932. splitbutton: renderFromBridge(createSplitButton, (s, extras) => renderSplitButton(s, extras.backstage.shared)),
  19933. grouptoolbarbutton: renderFromBridge(createGroupToolbarButton, (s, extras, editor) => {
  19934. const buttons = editor.ui.registry.getAll().buttons;
  19935. const identify = toolbar => identifyButtons(editor, {
  19936. buttons,
  19937. toolbar,
  19938. allowToolbarGroups: false
  19939. }, extras, Optional.none());
  19940. const attributes = { [Attribute]: extras.backstage.shared.header.isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop };
  19941. switch (getToolbarMode(editor)) {
  19942. case ToolbarMode$1.floating:
  19943. return renderFloatingToolbarButton(s, extras.backstage, identify, attributes);
  19944. default:
  19945. throw new Error('Toolbar groups are only supported when using floating toolbar mode');
  19946. }
  19947. }),
  19948. styleSelectButton: (editor, extras) => createStylesButton(editor, extras.backstage),
  19949. fontsizeSelectButton: (editor, extras) => createFontSizeButton(editor, extras.backstage),
  19950. fontSelectButton: (editor, extras) => createFontFamilyButton(editor, extras.backstage),
  19951. formatButton: (editor, extras) => createBlocksButton(editor, extras.backstage),
  19952. alignMenuButton: (editor, extras) => createAlignButton(editor, extras.backstage)
  19953. };
  19954. const extractFrom = (spec, extras, editor) => get$g(types, spec.type).fold(() => {
  19955. console.error('skipping button defined by', spec);
  19956. return Optional.none();
  19957. }, render => Optional.some(render(spec, extras, editor)));
  19958. const bespokeButtons = {
  19959. styles: types.styleSelectButton,
  19960. fontsize: types.fontsizeSelectButton,
  19961. fontfamily: types.fontSelectButton,
  19962. blocks: types.formatButton,
  19963. align: types.alignMenuButton
  19964. };
  19965. const removeUnusedDefaults = buttons => {
  19966. const filteredItemGroups = map$2(defaultToolbar, group => {
  19967. const items = filter$2(group.items, subItem => has$2(buttons, subItem) || has$2(bespokeButtons, subItem));
  19968. return {
  19969. name: group.name,
  19970. items
  19971. };
  19972. });
  19973. return filter$2(filteredItemGroups, group => group.items.length > 0);
  19974. };
  19975. const convertStringToolbar = strToolbar => {
  19976. const groupsStrings = strToolbar.split('|');
  19977. return map$2(groupsStrings, g => ({ items: g.trim().split(' ') }));
  19978. };
  19979. const isToolbarGroupSettingArray = toolbar => isArrayOf(toolbar, t => has$2(t, 'name') && has$2(t, 'items'));
  19980. const createToolbar = toolbarConfig => {
  19981. const toolbar = toolbarConfig.toolbar;
  19982. const buttons = toolbarConfig.buttons;
  19983. if (toolbar === false) {
  19984. return [];
  19985. } else if (toolbar === undefined || toolbar === true) {
  19986. return removeUnusedDefaults(buttons);
  19987. } else if (isString(toolbar)) {
  19988. return convertStringToolbar(toolbar);
  19989. } else if (isToolbarGroupSettingArray(toolbar)) {
  19990. return toolbar;
  19991. } else {
  19992. console.error('Toolbar type should be string, string[], boolean or ToolbarGroup[]');
  19993. return [];
  19994. }
  19995. };
  19996. const lookupButton = (editor, buttons, toolbarItem, allowToolbarGroups, extras, 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, extras)).orThunk(() => Optional.none()), spec => {
  19997. if (spec.type === 'grouptoolbarbutton' && !allowToolbarGroups) {
  19998. console.warn(`Ignoring the '${ toolbarItem }' toolbar button. Group toolbar buttons are only supported when using floating toolbar mode and cannot be nested.`);
  19999. return Optional.none();
  20000. } else {
  20001. return extractFrom(spec, extras, editor);
  20002. }
  20003. });
  20004. const identifyButtons = (editor, toolbarConfig, extras, prefixes) => {
  20005. const toolbarGroups = createToolbar(toolbarConfig);
  20006. const groups = map$2(toolbarGroups, group => {
  20007. const items = bind$3(group.items, toolbarItem => toolbarItem.trim().length === 0 ? [] : lookupButton(editor, toolbarConfig.buttons, toolbarItem, toolbarConfig.allowToolbarGroups, extras, prefixes).toArray());
  20008. return {
  20009. title: Optional.from(editor.translate(group.name)),
  20010. items
  20011. };
  20012. });
  20013. return filter$2(groups, group => group.items.length > 0);
  20014. };
  20015. const setToolbar = (editor, uiComponents, rawUiConfig, backstage) => {
  20016. const comp = uiComponents.outerContainer;
  20017. const toolbarConfig = rawUiConfig.toolbar;
  20018. const toolbarButtonsConfig = rawUiConfig.buttons;
  20019. if (isArrayOf(toolbarConfig, isString)) {
  20020. const toolbars = toolbarConfig.map(t => {
  20021. const config = {
  20022. toolbar: t,
  20023. buttons: toolbarButtonsConfig,
  20024. allowToolbarGroups: rawUiConfig.allowToolbarGroups
  20025. };
  20026. return identifyButtons(editor, config, { backstage }, Optional.none());
  20027. });
  20028. OuterContainer.setToolbars(comp, toolbars);
  20029. } else {
  20030. OuterContainer.setToolbar(comp, identifyButtons(editor, rawUiConfig, { backstage }, Optional.none()));
  20031. }
  20032. };
  20033. const detection = detect$1();
  20034. const isiOS12 = detection.os.isiOS() && detection.os.version.major <= 12;
  20035. const setupEvents$1 = (editor, uiComponents) => {
  20036. const dom = editor.dom;
  20037. let contentWindow = editor.getWin();
  20038. const initialDocEle = editor.getDoc().documentElement;
  20039. const lastWindowDimensions = Cell(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
  20040. const lastDocumentDimensions = Cell(SugarPosition(initialDocEle.offsetWidth, initialDocEle.offsetHeight));
  20041. const resizeWindow = () => {
  20042. const outer = lastWindowDimensions.get();
  20043. if (outer.left !== contentWindow.innerWidth || outer.top !== contentWindow.innerHeight) {
  20044. lastWindowDimensions.set(SugarPosition(contentWindow.innerWidth, contentWindow.innerHeight));
  20045. fireResizeContent(editor);
  20046. }
  20047. };
  20048. const resizeDocument = () => {
  20049. const docEle = editor.getDoc().documentElement;
  20050. const inner = lastDocumentDimensions.get();
  20051. if (inner.left !== docEle.offsetWidth || inner.top !== docEle.offsetHeight) {
  20052. lastDocumentDimensions.set(SugarPosition(docEle.offsetWidth, docEle.offsetHeight));
  20053. fireResizeContent(editor);
  20054. }
  20055. };
  20056. const scroll = e => fireScrollContent(editor, e);
  20057. dom.bind(contentWindow, 'resize', resizeWindow);
  20058. dom.bind(contentWindow, 'scroll', scroll);
  20059. const elementLoad = capture(SugarElement.fromDom(editor.getBody()), 'load', resizeDocument);
  20060. const mothership = uiComponents.uiMothership.element;
  20061. editor.on('hide', () => {
  20062. set$8(mothership, 'display', 'none');
  20063. });
  20064. editor.on('show', () => {
  20065. remove$6(mothership, 'display');
  20066. });
  20067. editor.on('NodeChange', resizeDocument);
  20068. editor.on('remove', () => {
  20069. elementLoad.unbind();
  20070. dom.unbind(contentWindow, 'resize', resizeWindow);
  20071. dom.unbind(contentWindow, 'scroll', scroll);
  20072. contentWindow = null;
  20073. });
  20074. };
  20075. const render$1 = (editor, uiComponents, rawUiConfig, backstage, args) => {
  20076. const lastToolbarWidth = Cell(0);
  20077. const outerContainer = uiComponents.outerContainer;
  20078. iframe(editor);
  20079. const eTargetNode = SugarElement.fromDom(args.targetNode);
  20080. const uiRoot = getContentContainer(getRootNode(eTargetNode));
  20081. attachSystemAfter(eTargetNode, uiComponents.mothership);
  20082. attachSystem(uiRoot, uiComponents.uiMothership);
  20083. editor.on('PostRender', () => {
  20084. setToolbar(editor, uiComponents, rawUiConfig, backstage);
  20085. lastToolbarWidth.set(editor.getWin().innerWidth);
  20086. OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
  20087. OuterContainer.setSidebar(outerContainer, rawUiConfig.sidebar, getSidebarShow(editor));
  20088. setupEvents$1(editor, uiComponents);
  20089. });
  20090. const socket = OuterContainer.getSocket(outerContainer).getOrDie('Could not find expected socket element');
  20091. if (isiOS12) {
  20092. setAll(socket.element, {
  20093. 'overflow': 'scroll',
  20094. '-webkit-overflow-scrolling': 'touch'
  20095. });
  20096. const limit = first(() => {
  20097. editor.dispatch('ScrollContent');
  20098. }, 20);
  20099. const unbinder = bind(socket.element, 'scroll', limit.throttle);
  20100. editor.on('remove', unbinder.unbind);
  20101. }
  20102. setupReadonlyModeSwitch(editor, uiComponents);
  20103. editor.addCommand('ToggleSidebar', (_ui, value) => {
  20104. OuterContainer.toggleSidebar(outerContainer, value);
  20105. editor.dispatch('ToggleSidebar');
  20106. });
  20107. editor.addQueryValueHandler('ToggleSidebar', () => OuterContainer.whichSidebar(outerContainer));
  20108. const toolbarMode = getToolbarMode(editor);
  20109. const refreshDrawer = () => {
  20110. OuterContainer.refreshToolbar(uiComponents.outerContainer);
  20111. };
  20112. if (toolbarMode === ToolbarMode$1.sliding || toolbarMode === ToolbarMode$1.floating) {
  20113. editor.on('ResizeWindow ResizeEditor ResizeContent', () => {
  20114. const width = editor.getWin().innerWidth;
  20115. if (width !== lastToolbarWidth.get()) {
  20116. refreshDrawer();
  20117. lastToolbarWidth.set(width);
  20118. }
  20119. });
  20120. }
  20121. const api = {
  20122. setEnabled: state => {
  20123. broadcastReadonly(uiComponents, !state);
  20124. },
  20125. isEnabled: () => !Disabling.isDisabled(outerContainer)
  20126. };
  20127. return {
  20128. iframeContainer: socket.element.dom,
  20129. editorContainer: outerContainer.element.dom,
  20130. api
  20131. };
  20132. };
  20133. var Iframe = /*#__PURE__*/Object.freeze({
  20134. __proto__: null,
  20135. render: render$1
  20136. });
  20137. const parseToInt = val => {
  20138. const re = /^[0-9\.]+(|px)$/i;
  20139. if (re.test('' + val)) {
  20140. return Optional.some(parseInt('' + val, 10));
  20141. }
  20142. return Optional.none();
  20143. };
  20144. const numToPx = val => isNumber(val) ? val + 'px' : val;
  20145. const calcCappedSize = (size, minSize, maxSize) => {
  20146. const minOverride = minSize.filter(min => size < min);
  20147. const maxOverride = maxSize.filter(max => size > max);
  20148. return minOverride.or(maxOverride).getOr(size);
  20149. };
  20150. const getHeight = editor => {
  20151. const baseHeight = getHeightOption(editor);
  20152. const minHeight = getMinHeightOption(editor);
  20153. const maxHeight = getMaxHeightOption(editor);
  20154. return parseToInt(baseHeight).map(height => calcCappedSize(height, minHeight, maxHeight));
  20155. };
  20156. const getHeightWithFallback = editor => {
  20157. const height = getHeight(editor);
  20158. return height.getOr(getHeightOption(editor));
  20159. };
  20160. const getWidth = editor => {
  20161. const baseWidth = getWidthOption(editor);
  20162. const minWidth = getMinWidthOption(editor);
  20163. const maxWidth = getMaxWidthOption(editor);
  20164. return parseToInt(baseWidth).map(width => calcCappedSize(width, minWidth, maxWidth));
  20165. };
  20166. const getWidthWithFallback = editor => {
  20167. const width = getWidth(editor);
  20168. return width.getOr(getWidthOption(editor));
  20169. };
  20170. const {ToolbarLocation, ToolbarMode} = Options;
  20171. const InlineHeader = (editor, targetElm, uiComponents, backstage, floatContainer) => {
  20172. const {uiMothership, outerContainer} = uiComponents;
  20173. const DOM = global$7.DOM;
  20174. const useFixedToolbarContainer = useFixedContainer(editor);
  20175. const isSticky = isStickyToolbar(editor);
  20176. const editorMaxWidthOpt = getMaxWidthOption(editor).or(getWidth(editor));
  20177. const headerBackstage = backstage.shared.header;
  20178. const isPositionedAtTop = headerBackstage.isPositionedAtTop;
  20179. const toolbarMode = getToolbarMode(editor);
  20180. const isSplitToolbar = toolbarMode === ToolbarMode.sliding || toolbarMode === ToolbarMode.floating;
  20181. const visible = Cell(false);
  20182. const isVisible = () => visible.get() && !editor.removed;
  20183. const calcToolbarOffset = toolbar => isSplitToolbar ? toolbar.fold(constant$1(0), tbar => tbar.components().length > 1 ? get$d(tbar.components()[1].element) : 0) : 0;
  20184. const calcMode = container => {
  20185. switch (getToolbarLocation(editor)) {
  20186. case ToolbarLocation.auto:
  20187. const toolbar = OuterContainer.getToolbar(outerContainer);
  20188. const offset = calcToolbarOffset(toolbar);
  20189. const toolbarHeight = get$d(container.element) - offset;
  20190. const targetBounds = box$1(targetElm);
  20191. const roomAtTop = targetBounds.y > toolbarHeight;
  20192. if (roomAtTop) {
  20193. return 'top';
  20194. } else {
  20195. const doc = documentElement(targetElm);
  20196. const docHeight = Math.max(doc.dom.scrollHeight, get$d(doc));
  20197. const roomAtBottom = targetBounds.bottom < docHeight - toolbarHeight;
  20198. if (roomAtBottom) {
  20199. return 'bottom';
  20200. } else {
  20201. const winBounds = win();
  20202. const isRoomAtBottomViewport = winBounds.bottom < targetBounds.bottom - toolbarHeight;
  20203. return isRoomAtBottomViewport ? 'bottom' : 'top';
  20204. }
  20205. }
  20206. case ToolbarLocation.bottom:
  20207. return 'bottom';
  20208. case ToolbarLocation.top:
  20209. default:
  20210. return 'top';
  20211. }
  20212. };
  20213. const setupMode = mode => {
  20214. const container = floatContainer.get();
  20215. Docking.setModes(container, [mode]);
  20216. headerBackstage.setDockingMode(mode);
  20217. const verticalDir = isPositionedAtTop() ? AttributeValue.TopToBottom : AttributeValue.BottomToTop;
  20218. set$9(container.element, Attribute, verticalDir);
  20219. };
  20220. const updateChromeWidth = () => {
  20221. const maxWidth = editorMaxWidthOpt.getOrThunk(() => {
  20222. const bodyMargin = parseToInt(get$e(body(), 'margin-left')).getOr(0);
  20223. return get$c(body()) - absolute$3(targetElm).left + bodyMargin;
  20224. });
  20225. set$8(floatContainer.get().element, 'max-width', maxWidth + 'px');
  20226. };
  20227. const updateChromePosition = () => {
  20228. const toolbar = OuterContainer.getToolbar(outerContainer);
  20229. const offset = calcToolbarOffset(toolbar);
  20230. const targetBounds = box$1(targetElm);
  20231. const top = isPositionedAtTop() ? Math.max(targetBounds.y - get$d(floatContainer.get().element) + offset, 0) : targetBounds.bottom;
  20232. setAll(outerContainer.element, {
  20233. position: 'absolute',
  20234. top: Math.round(top) + 'px',
  20235. left: Math.round(targetBounds.x) + 'px'
  20236. });
  20237. };
  20238. const repositionPopups$1 = () => {
  20239. uiMothership.broadcastOn([repositionPopups()], {});
  20240. };
  20241. const updateChromeUi = (resetDocking = false) => {
  20242. if (!isVisible()) {
  20243. return;
  20244. }
  20245. if (!useFixedToolbarContainer) {
  20246. updateChromeWidth();
  20247. }
  20248. if (isSplitToolbar) {
  20249. OuterContainer.refreshToolbar(outerContainer);
  20250. }
  20251. if (!useFixedToolbarContainer) {
  20252. updateChromePosition();
  20253. }
  20254. if (isSticky) {
  20255. const floatContainerComp = floatContainer.get();
  20256. resetDocking ? Docking.reset(floatContainerComp) : Docking.refresh(floatContainerComp);
  20257. }
  20258. repositionPopups$1();
  20259. };
  20260. const updateMode = (updateUi = true) => {
  20261. if (useFixedToolbarContainer || !isSticky || !isVisible()) {
  20262. return;
  20263. }
  20264. const currentMode = headerBackstage.getDockingMode();
  20265. const newMode = calcMode(floatContainer.get());
  20266. if (newMode !== currentMode) {
  20267. setupMode(newMode);
  20268. if (updateUi) {
  20269. updateChromeUi(true);
  20270. }
  20271. }
  20272. };
  20273. const show = () => {
  20274. visible.set(true);
  20275. set$8(outerContainer.element, 'display', 'flex');
  20276. DOM.addClass(editor.getBody(), 'mce-edit-focus');
  20277. remove$6(uiMothership.element, 'display');
  20278. updateMode(false);
  20279. updateChromeUi();
  20280. };
  20281. const hide = () => {
  20282. visible.set(false);
  20283. if (uiComponents.outerContainer) {
  20284. set$8(outerContainer.element, 'display', 'none');
  20285. DOM.removeClass(editor.getBody(), 'mce-edit-focus');
  20286. }
  20287. set$8(uiMothership.element, 'display', 'none');
  20288. };
  20289. return {
  20290. isVisible,
  20291. isPositionedAtTop,
  20292. show,
  20293. hide,
  20294. update: updateChromeUi,
  20295. updateMode,
  20296. repositionPopups: repositionPopups$1
  20297. };
  20298. };
  20299. const getTargetPosAndBounds = (targetElm, isToolbarTop) => {
  20300. const bounds = box$1(targetElm);
  20301. return {
  20302. pos: isToolbarTop ? bounds.y : bounds.bottom,
  20303. bounds
  20304. };
  20305. };
  20306. const setupEvents = (editor, targetElm, ui, toolbarPersist) => {
  20307. const prevPosAndBounds = Cell(getTargetPosAndBounds(targetElm, ui.isPositionedAtTop()));
  20308. const resizeContent = e => {
  20309. const {pos, bounds} = getTargetPosAndBounds(targetElm, ui.isPositionedAtTop());
  20310. const {
  20311. pos: prevPos,
  20312. bounds: prevBounds
  20313. } = prevPosAndBounds.get();
  20314. const hasResized = bounds.height !== prevBounds.height || bounds.width !== prevBounds.width;
  20315. prevPosAndBounds.set({
  20316. pos,
  20317. bounds
  20318. });
  20319. if (hasResized) {
  20320. fireResizeContent(editor, e);
  20321. }
  20322. if (ui.isVisible()) {
  20323. if (prevPos !== pos) {
  20324. ui.update(true);
  20325. } else if (hasResized) {
  20326. ui.updateMode();
  20327. ui.repositionPopups();
  20328. }
  20329. }
  20330. };
  20331. if (!toolbarPersist) {
  20332. editor.on('activate', ui.show);
  20333. editor.on('deactivate', ui.hide);
  20334. }
  20335. editor.on('SkinLoaded ResizeWindow', () => ui.update(true));
  20336. editor.on('NodeChange keydown', e => {
  20337. requestAnimationFrame(() => resizeContent(e));
  20338. });
  20339. editor.on('ScrollWindow', () => ui.updateMode());
  20340. const elementLoad = unbindable();
  20341. elementLoad.set(capture(SugarElement.fromDom(editor.getBody()), 'load', resizeContent));
  20342. editor.on('remove', () => {
  20343. elementLoad.clear();
  20344. });
  20345. };
  20346. const render = (editor, uiComponents, rawUiConfig, backstage, args) => {
  20347. const {mothership, uiMothership, outerContainer} = uiComponents;
  20348. const floatContainer = Cell(null);
  20349. const targetElm = SugarElement.fromDom(args.targetNode);
  20350. const ui = InlineHeader(editor, targetElm, uiComponents, backstage, floatContainer);
  20351. const toolbarPersist = isToolbarPersist(editor);
  20352. inline(editor);
  20353. const render = () => {
  20354. if (floatContainer.get()) {
  20355. ui.show();
  20356. return;
  20357. }
  20358. floatContainer.set(OuterContainer.getHeader(outerContainer).getOrDie());
  20359. const uiContainer = getUiContainer(editor);
  20360. attachSystem(uiContainer, mothership);
  20361. attachSystem(uiContainer, uiMothership);
  20362. setToolbar(editor, uiComponents, rawUiConfig, backstage);
  20363. OuterContainer.setMenubar(outerContainer, identifyMenus(editor, rawUiConfig));
  20364. ui.show();
  20365. setupEvents(editor, targetElm, ui, toolbarPersist);
  20366. editor.nodeChanged();
  20367. };
  20368. editor.on('show', render);
  20369. editor.on('hide', ui.hide);
  20370. if (!toolbarPersist) {
  20371. editor.on('focus', render);
  20372. editor.on('blur', ui.hide);
  20373. }
  20374. editor.on('init', () => {
  20375. if (editor.hasFocus() || toolbarPersist) {
  20376. render();
  20377. }
  20378. });
  20379. setupReadonlyModeSwitch(editor, uiComponents);
  20380. const api = {
  20381. show: () => {
  20382. render();
  20383. },
  20384. hide: () => {
  20385. ui.hide();
  20386. },
  20387. setEnabled: state => {
  20388. broadcastReadonly(uiComponents, !state);
  20389. },
  20390. isEnabled: () => !Disabling.isDisabled(outerContainer)
  20391. };
  20392. return {
  20393. editorContainer: outerContainer.element.dom,
  20394. api
  20395. };
  20396. };
  20397. var Inline = /*#__PURE__*/Object.freeze({
  20398. __proto__: null,
  20399. render: render
  20400. });
  20401. const showContextToolbarEvent = 'contexttoolbar-show';
  20402. const hideContextToolbarEvent = 'contexttoolbar-hide';
  20403. const getFormApi = input => ({
  20404. hide: () => emit(input, sandboxClose()),
  20405. getValue: () => Representing.getValue(input)
  20406. });
  20407. const runOnExecute = (memInput, original) => run$1(internalToolbarButtonExecute, (comp, se) => {
  20408. const input = memInput.get(comp);
  20409. const formApi = getFormApi(input);
  20410. original.onAction(formApi, se.event.buttonApi);
  20411. });
  20412. const renderContextButton = (memInput, button, extras) => {
  20413. const {primary, ...rest} = button.original;
  20414. const bridged = getOrDie(createToolbarButton({
  20415. ...rest,
  20416. type: 'button',
  20417. onAction: noop
  20418. }));
  20419. return renderToolbarButtonWith(bridged, extras.backstage.shared.providers, [runOnExecute(memInput, button)]);
  20420. };
  20421. const renderContextToggleButton = (memInput, button, extras) => {
  20422. const {primary, ...rest} = button.original;
  20423. const bridged = getOrDie(createToggleButton({
  20424. ...rest,
  20425. type: 'togglebutton',
  20426. onAction: noop
  20427. }));
  20428. return renderToolbarToggleButtonWith(bridged, extras.backstage.shared.providers, [runOnExecute(memInput, button)]);
  20429. };
  20430. const generateOne = (memInput, button, providersBackstage) => {
  20431. const extras = { backstage: { shared: { providers: providersBackstage } } };
  20432. if (button.type === 'contextformtogglebutton') {
  20433. return renderContextToggleButton(memInput, button, extras);
  20434. } else {
  20435. return renderContextButton(memInput, button, extras);
  20436. }
  20437. };
  20438. const generate = (memInput, buttons, providersBackstage) => {
  20439. const mementos = map$2(buttons, button => record(generateOne(memInput, button, providersBackstage)));
  20440. const asSpecs = () => map$2(mementos, mem => mem.asSpec());
  20441. const findPrimary = compInSystem => findMap(buttons, (button, i) => {
  20442. if (button.primary) {
  20443. return Optional.from(mementos[i]).bind(mem => mem.getOpt(compInSystem)).filter(not(Disabling.isDisabled));
  20444. } else {
  20445. return Optional.none();
  20446. }
  20447. });
  20448. return {
  20449. asSpecs,
  20450. findPrimary
  20451. };
  20452. };
  20453. const buildInitGroups = (ctx, providers) => {
  20454. const inputAttributes = ctx.label.fold(() => ({}), label => ({ 'aria-label': label }));
  20455. const memInput = record(Input.sketch({
  20456. inputClasses: [
  20457. 'tox-toolbar-textfield',
  20458. 'tox-toolbar-nav-js'
  20459. ],
  20460. data: ctx.initValue(),
  20461. inputAttributes,
  20462. selectOnFocus: true,
  20463. inputBehaviours: derive$1([Keying.config({
  20464. mode: 'special',
  20465. onEnter: input => commands.findPrimary(input).map(primary => {
  20466. emitExecute(primary);
  20467. return true;
  20468. }),
  20469. onLeft: (comp, se) => {
  20470. se.cut();
  20471. return Optional.none();
  20472. },
  20473. onRight: (comp, se) => {
  20474. se.cut();
  20475. return Optional.none();
  20476. }
  20477. })])
  20478. }));
  20479. const commands = generate(memInput, ctx.commands, providers);
  20480. return [
  20481. {
  20482. title: Optional.none(),
  20483. items: [memInput.asSpec()]
  20484. },
  20485. {
  20486. title: Optional.none(),
  20487. items: commands.asSpecs()
  20488. }
  20489. ];
  20490. };
  20491. const renderContextForm = (toolbarType, ctx, providers) => renderToolbar({
  20492. type: toolbarType,
  20493. uid: generate$6('context-toolbar'),
  20494. initGroups: buildInitGroups(ctx, providers),
  20495. onEscape: Optional.none,
  20496. cyclicKeying: true,
  20497. providers
  20498. });
  20499. const ContextForm = {
  20500. renderContextForm,
  20501. buildInitGroups
  20502. };
  20503. const isVerticalOverlap = (a, b, threshold = 0.01) => b.bottom - a.y >= threshold && a.bottom - b.y >= threshold;
  20504. const getRangeRect = rng => {
  20505. const rect = rng.getBoundingClientRect();
  20506. if (rect.height <= 0 && rect.width <= 0) {
  20507. const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset).element;
  20508. const elm = isText(leaf$1) ? parent(leaf$1) : Optional.some(leaf$1);
  20509. return elm.filter(isElement$1).map(e => e.dom.getBoundingClientRect()).getOr(rect);
  20510. } else {
  20511. return rect;
  20512. }
  20513. };
  20514. const getSelectionBounds = editor => {
  20515. const rng = editor.selection.getRng();
  20516. const rect = getRangeRect(rng);
  20517. if (editor.inline) {
  20518. const scroll = get$b();
  20519. return bounds(scroll.left + rect.left, scroll.top + rect.top, rect.width, rect.height);
  20520. } else {
  20521. const bodyPos = absolute$2(SugarElement.fromDom(editor.getBody()));
  20522. return bounds(bodyPos.x + rect.left, bodyPos.y + rect.top, rect.width, rect.height);
  20523. }
  20524. };
  20525. const getAnchorElementBounds = (editor, lastElement) => lastElement.filter(inBody).map(absolute$2).getOrThunk(() => getSelectionBounds(editor));
  20526. const getHorizontalBounds = (contentAreaBox, viewportBounds, margin) => {
  20527. const x = Math.max(contentAreaBox.x + margin, viewportBounds.x);
  20528. const right = Math.min(contentAreaBox.right - margin, viewportBounds.right);
  20529. return {
  20530. x,
  20531. width: right - x
  20532. };
  20533. };
  20534. const getVerticalBounds = (editor, contentAreaBox, viewportBounds, isToolbarLocationTop, toolbarType, margin) => {
  20535. const container = SugarElement.fromDom(editor.getContainer());
  20536. const header = descendant(container, '.tox-editor-header').getOr(container);
  20537. const headerBox = box$1(header);
  20538. const isToolbarBelowContentArea = headerBox.y >= contentAreaBox.bottom;
  20539. const isToolbarAbove = isToolbarLocationTop && !isToolbarBelowContentArea;
  20540. if (editor.inline && isToolbarAbove) {
  20541. return {
  20542. y: Math.max(headerBox.bottom + margin, viewportBounds.y),
  20543. bottom: viewportBounds.bottom
  20544. };
  20545. }
  20546. if (editor.inline && !isToolbarAbove) {
  20547. return {
  20548. y: viewportBounds.y,
  20549. bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
  20550. };
  20551. }
  20552. const containerBounds = toolbarType === 'line' ? box$1(container) : contentAreaBox;
  20553. if (isToolbarAbove) {
  20554. return {
  20555. y: Math.max(headerBox.bottom + margin, viewportBounds.y),
  20556. bottom: Math.min(containerBounds.bottom - margin, viewportBounds.bottom)
  20557. };
  20558. }
  20559. return {
  20560. y: Math.max(containerBounds.y + margin, viewportBounds.y),
  20561. bottom: Math.min(headerBox.y - margin, viewportBounds.bottom)
  20562. };
  20563. };
  20564. const getContextToolbarBounds = (editor, sharedBackstage, toolbarType, margin = 0) => {
  20565. const viewportBounds = getBounds$3(window);
  20566. const contentAreaBox = box$1(SugarElement.fromDom(editor.getContentAreaContainer()));
  20567. const toolbarOrMenubarEnabled = isMenubarEnabled(editor) || isToolbarEnabled(editor) || isMultipleToolbars(editor);
  20568. const {x, width} = getHorizontalBounds(contentAreaBox, viewportBounds, margin);
  20569. if (editor.inline && !toolbarOrMenubarEnabled) {
  20570. return bounds(x, viewportBounds.y, width, viewportBounds.height);
  20571. } else {
  20572. const isToolbarTop = sharedBackstage.header.isPositionedAtTop();
  20573. const {y, bottom} = getVerticalBounds(editor, contentAreaBox, viewportBounds, isToolbarTop, toolbarType, margin);
  20574. return bounds(x, y, width, bottom - y);
  20575. }
  20576. };
  20577. const bubbleSize$1 = 12;
  20578. const bubbleAlignments$1 = {
  20579. valignCentre: [],
  20580. alignCentre: [],
  20581. alignLeft: ['tox-pop--align-left'],
  20582. alignRight: ['tox-pop--align-right'],
  20583. right: ['tox-pop--right'],
  20584. left: ['tox-pop--left'],
  20585. bottom: ['tox-pop--bottom'],
  20586. top: ['tox-pop--top'],
  20587. inset: ['tox-pop--inset']
  20588. };
  20589. const anchorOverrides = {
  20590. maxHeightFunction: expandable$1(),
  20591. maxWidthFunction: expandable()
  20592. };
  20593. const isEntireElementSelected = (editor, elem) => {
  20594. const rng = editor.selection.getRng();
  20595. const leaf$1 = leaf(SugarElement.fromDom(rng.startContainer), rng.startOffset);
  20596. return rng.startContainer === rng.endContainer && rng.startOffset === rng.endOffset - 1 && eq(leaf$1.element, elem);
  20597. };
  20598. const preservePosition = (elem, position, f) => {
  20599. const currentPosition = getRaw(elem, 'position');
  20600. set$8(elem, 'position', position);
  20601. const result = f(elem);
  20602. currentPosition.each(pos => set$8(elem, 'position', pos));
  20603. return result;
  20604. };
  20605. const shouldUseInsetLayouts = position => position === 'node';
  20606. const determineInsetLayout = (editor, contextbar, elem, data, bounds) => {
  20607. const selectionBounds = getSelectionBounds(editor);
  20608. const isSameAnchorElement = data.lastElement().exists(prev => eq(elem, prev));
  20609. if (isEntireElementSelected(editor, elem)) {
  20610. return isSameAnchorElement ? preserve : north;
  20611. } else if (isSameAnchorElement) {
  20612. return preservePosition(contextbar, data.getMode(), () => {
  20613. const isOverlapping = isVerticalOverlap(selectionBounds, box$1(contextbar));
  20614. return isOverlapping && !data.isReposition() ? flip : preserve;
  20615. });
  20616. } else {
  20617. const yBounds = data.getMode() === 'fixed' ? bounds.y + get$b().top : bounds.y;
  20618. const contextbarHeight = get$d(contextbar) + bubbleSize$1;
  20619. return yBounds + contextbarHeight <= selectionBounds.y ? north : south;
  20620. }
  20621. };
  20622. const getAnchorSpec$2 = (editor, mobile, data, position) => {
  20623. const smartInsetLayout = elem => (anchor, element, bubbles, placee, bounds) => {
  20624. const layout = determineInsetLayout(editor, placee, elem, data, bounds);
  20625. const newAnchor = {
  20626. ...anchor,
  20627. y: bounds.y,
  20628. height: bounds.height
  20629. };
  20630. return {
  20631. ...layout(newAnchor, element, bubbles, placee, bounds),
  20632. alwaysFit: true
  20633. };
  20634. };
  20635. const getInsetLayouts = elem => shouldUseInsetLayouts(position) ? [smartInsetLayout(elem)] : [];
  20636. const desktopAnchorSpecLayouts = {
  20637. onLtr: elem => [
  20638. north$2,
  20639. south$2,
  20640. northeast$2,
  20641. southeast$2,
  20642. northwest$2,
  20643. southwest$2
  20644. ].concat(getInsetLayouts(elem)),
  20645. onRtl: elem => [
  20646. north$2,
  20647. south$2,
  20648. northwest$2,
  20649. southwest$2,
  20650. northeast$2,
  20651. southeast$2
  20652. ].concat(getInsetLayouts(elem))
  20653. };
  20654. const mobileAnchorSpecLayouts = {
  20655. onLtr: elem => [
  20656. south$2,
  20657. southeast$2,
  20658. southwest$2,
  20659. northeast$2,
  20660. northwest$2,
  20661. north$2
  20662. ].concat(getInsetLayouts(elem)),
  20663. onRtl: elem => [
  20664. south$2,
  20665. southwest$2,
  20666. southeast$2,
  20667. northwest$2,
  20668. northeast$2,
  20669. north$2
  20670. ].concat(getInsetLayouts(elem))
  20671. };
  20672. return mobile ? mobileAnchorSpecLayouts : desktopAnchorSpecLayouts;
  20673. };
  20674. const getAnchorLayout = (editor, position, isTouch, data) => {
  20675. if (position === 'line') {
  20676. return {
  20677. bubble: nu$5(bubbleSize$1, 0, bubbleAlignments$1),
  20678. layouts: {
  20679. onLtr: () => [east$2],
  20680. onRtl: () => [west$2]
  20681. },
  20682. overrides: anchorOverrides
  20683. };
  20684. } else {
  20685. return {
  20686. bubble: nu$5(0, bubbleSize$1, bubbleAlignments$1, 1 / bubbleSize$1),
  20687. layouts: getAnchorSpec$2(editor, isTouch, data, position),
  20688. overrides: anchorOverrides
  20689. };
  20690. }
  20691. };
  20692. const matchTargetWith = (elem, candidates) => {
  20693. const ctxs = filter$2(candidates, toolbarApi => toolbarApi.predicate(elem.dom));
  20694. const {pass, fail} = partition$3(ctxs, t => t.type === 'contexttoolbar');
  20695. return {
  20696. contextToolbars: pass,
  20697. contextForms: fail
  20698. };
  20699. };
  20700. const filterByPositionForStartNode = toolbars => {
  20701. if (toolbars.length <= 1) {
  20702. return toolbars;
  20703. } else {
  20704. const doesPositionExist = value => exists(toolbars, t => t.position === value);
  20705. const filterToolbarsByPosition = value => filter$2(toolbars, t => t.position === value);
  20706. const hasSelectionToolbars = doesPositionExist('selection');
  20707. const hasNodeToolbars = doesPositionExist('node');
  20708. if (hasSelectionToolbars || hasNodeToolbars) {
  20709. if (hasNodeToolbars && hasSelectionToolbars) {
  20710. const nodeToolbars = filterToolbarsByPosition('node');
  20711. const selectionToolbars = map$2(filterToolbarsByPosition('selection'), t => ({
  20712. ...t,
  20713. position: 'node'
  20714. }));
  20715. return nodeToolbars.concat(selectionToolbars);
  20716. } else {
  20717. return hasSelectionToolbars ? filterToolbarsByPosition('selection') : filterToolbarsByPosition('node');
  20718. }
  20719. } else {
  20720. return filterToolbarsByPosition('line');
  20721. }
  20722. }
  20723. };
  20724. const filterByPositionForAncestorNode = toolbars => {
  20725. if (toolbars.length <= 1) {
  20726. return toolbars;
  20727. } else {
  20728. const findPosition = value => find$5(toolbars, t => t.position === value);
  20729. const basePosition = findPosition('selection').orThunk(() => findPosition('node')).orThunk(() => findPosition('line')).map(t => t.position);
  20730. return basePosition.fold(() => [], pos => filter$2(toolbars, t => t.position === pos));
  20731. }
  20732. };
  20733. const matchStartNode = (elem, nodeCandidates, editorCandidates) => {
  20734. const nodeMatches = matchTargetWith(elem, nodeCandidates);
  20735. if (nodeMatches.contextForms.length > 0) {
  20736. return Optional.some({
  20737. elem,
  20738. toolbars: [nodeMatches.contextForms[0]]
  20739. });
  20740. } else {
  20741. const editorMatches = matchTargetWith(elem, editorCandidates);
  20742. if (editorMatches.contextForms.length > 0) {
  20743. return Optional.some({
  20744. elem,
  20745. toolbars: [editorMatches.contextForms[0]]
  20746. });
  20747. } else if (nodeMatches.contextToolbars.length > 0 || editorMatches.contextToolbars.length > 0) {
  20748. const toolbars = filterByPositionForStartNode(nodeMatches.contextToolbars.concat(editorMatches.contextToolbars));
  20749. return Optional.some({
  20750. elem,
  20751. toolbars
  20752. });
  20753. } else {
  20754. return Optional.none();
  20755. }
  20756. }
  20757. };
  20758. const matchAncestor = (isRoot, startNode, scopes) => {
  20759. if (isRoot(startNode)) {
  20760. return Optional.none();
  20761. } else {
  20762. return ancestor$2(startNode, ancestorElem => {
  20763. if (isElement$1(ancestorElem)) {
  20764. const {contextToolbars, contextForms} = matchTargetWith(ancestorElem, scopes.inNodeScope);
  20765. const toolbars = contextForms.length > 0 ? contextForms : filterByPositionForAncestorNode(contextToolbars);
  20766. return toolbars.length > 0 ? Optional.some({
  20767. elem: ancestorElem,
  20768. toolbars
  20769. }) : Optional.none();
  20770. } else {
  20771. return Optional.none();
  20772. }
  20773. }, isRoot);
  20774. }
  20775. };
  20776. const lookup$1 = (scopes, editor) => {
  20777. const rootElem = SugarElement.fromDom(editor.getBody());
  20778. const isRoot = elem => eq(elem, rootElem);
  20779. const isOutsideRoot = startNode => !isRoot(startNode) && !contains(rootElem, startNode);
  20780. const startNode = SugarElement.fromDom(editor.selection.getNode());
  20781. if (isOutsideRoot(startNode)) {
  20782. return Optional.none();
  20783. }
  20784. return matchStartNode(startNode, scopes.inNodeScope, scopes.inEditorScope).orThunk(() => matchAncestor(isRoot, startNode, scopes));
  20785. };
  20786. const categorise = (contextToolbars, navigate) => {
  20787. const forms = {};
  20788. const inNodeScope = [];
  20789. const inEditorScope = [];
  20790. const formNavigators = {};
  20791. const lookupTable = {};
  20792. const registerForm = (key, toolbarSpec) => {
  20793. const contextForm = getOrDie(createContextForm(toolbarSpec));
  20794. forms[key] = contextForm;
  20795. contextForm.launch.map(launch => {
  20796. formNavigators['form:' + key + ''] = {
  20797. ...toolbarSpec.launch,
  20798. type: launch.type === 'contextformtogglebutton' ? 'togglebutton' : 'button',
  20799. onAction: () => {
  20800. navigate(contextForm);
  20801. }
  20802. };
  20803. });
  20804. if (contextForm.scope === 'editor') {
  20805. inEditorScope.push(contextForm);
  20806. } else {
  20807. inNodeScope.push(contextForm);
  20808. }
  20809. lookupTable[key] = contextForm;
  20810. };
  20811. const registerToolbar = (key, toolbarSpec) => {
  20812. createContextToolbar(toolbarSpec).each(contextToolbar => {
  20813. if (toolbarSpec.scope === 'editor') {
  20814. inEditorScope.push(contextToolbar);
  20815. } else {
  20816. inNodeScope.push(contextToolbar);
  20817. }
  20818. lookupTable[key] = contextToolbar;
  20819. });
  20820. };
  20821. const keys$1 = keys(contextToolbars);
  20822. each$1(keys$1, key => {
  20823. const toolbarApi = contextToolbars[key];
  20824. if (toolbarApi.type === 'contextform') {
  20825. registerForm(key, toolbarApi);
  20826. } else if (toolbarApi.type === 'contexttoolbar') {
  20827. registerToolbar(key, toolbarApi);
  20828. }
  20829. });
  20830. return {
  20831. forms,
  20832. inNodeScope,
  20833. inEditorScope,
  20834. lookupTable,
  20835. formNavigators
  20836. };
  20837. };
  20838. const forwardSlideEvent = generate$6('forward-slide');
  20839. const backSlideEvent = generate$6('backward-slide');
  20840. const changeSlideEvent = generate$6('change-slide-event');
  20841. const resizingClass = 'tox-pop--resizing';
  20842. const renderContextToolbar = spec => {
  20843. const stack = Cell([]);
  20844. return InlineView.sketch({
  20845. dom: {
  20846. tag: 'div',
  20847. classes: ['tox-pop']
  20848. },
  20849. fireDismissalEventInstead: { event: 'doNotDismissYet' },
  20850. onShow: comp => {
  20851. stack.set([]);
  20852. InlineView.getContent(comp).each(c => {
  20853. remove$6(c.element, 'visibility');
  20854. });
  20855. remove$2(comp.element, resizingClass);
  20856. remove$6(comp.element, 'width');
  20857. },
  20858. inlineBehaviours: derive$1([
  20859. config('context-toolbar-events', [
  20860. runOnSource(transitionend(), (comp, se) => {
  20861. if (se.event.raw.propertyName === 'width') {
  20862. remove$2(comp.element, resizingClass);
  20863. remove$6(comp.element, 'width');
  20864. }
  20865. }),
  20866. run$1(changeSlideEvent, (comp, se) => {
  20867. const elem = comp.element;
  20868. remove$6(elem, 'width');
  20869. const currentWidth = get$c(elem);
  20870. InlineView.setContent(comp, se.event.contents);
  20871. add$2(elem, resizingClass);
  20872. const newWidth = get$c(elem);
  20873. set$8(elem, 'width', currentWidth + 'px');
  20874. InlineView.getContent(comp).each(newContents => {
  20875. se.event.focus.bind(f => {
  20876. focus$3(f);
  20877. return search(elem);
  20878. }).orThunk(() => {
  20879. Keying.focusIn(newContents);
  20880. return active$1(getRootNode(elem));
  20881. });
  20882. });
  20883. setTimeout(() => {
  20884. set$8(comp.element, 'width', newWidth + 'px');
  20885. }, 0);
  20886. }),
  20887. run$1(forwardSlideEvent, (comp, se) => {
  20888. InlineView.getContent(comp).each(oldContents => {
  20889. stack.set(stack.get().concat([{
  20890. bar: oldContents,
  20891. focus: active$1(getRootNode(comp.element))
  20892. }]));
  20893. });
  20894. emitWith(comp, changeSlideEvent, {
  20895. contents: se.event.forwardContents,
  20896. focus: Optional.none()
  20897. });
  20898. }),
  20899. run$1(backSlideEvent, (comp, _se) => {
  20900. last$1(stack.get()).each(last => {
  20901. stack.set(stack.get().slice(0, stack.get().length - 1));
  20902. emitWith(comp, changeSlideEvent, {
  20903. contents: premade(last.bar),
  20904. focus: last.focus
  20905. });
  20906. });
  20907. })
  20908. ]),
  20909. Keying.config({
  20910. mode: 'special',
  20911. onEscape: comp => last$1(stack.get()).fold(() => spec.onEscape(), _ => {
  20912. emit(comp, backSlideEvent);
  20913. return Optional.some(true);
  20914. })
  20915. })
  20916. ]),
  20917. lazySink: () => Result.value(spec.sink)
  20918. });
  20919. };
  20920. const transitionClass = 'tox-pop--transition';
  20921. const register$9 = (editor, registryContextToolbars, sink, extras) => {
  20922. const backstage = extras.backstage;
  20923. const sharedBackstage = backstage.shared;
  20924. const isTouch = detect$1().deviceType.isTouch;
  20925. const lastElement = value$2();
  20926. const lastTrigger = value$2();
  20927. const lastContextPosition = value$2();
  20928. const contextbar = build$1(renderContextToolbar({
  20929. sink,
  20930. onEscape: () => {
  20931. editor.focus();
  20932. return Optional.some(true);
  20933. }
  20934. }));
  20935. const getBounds = () => {
  20936. const position = lastContextPosition.get().getOr('node');
  20937. const margin = shouldUseInsetLayouts(position) ? 1 : 0;
  20938. return getContextToolbarBounds(editor, sharedBackstage, position, margin);
  20939. };
  20940. const canLaunchToolbar = () => {
  20941. return !editor.removed && !(isTouch() && backstage.isContextMenuOpen());
  20942. };
  20943. const isSameLaunchElement = elem => is$1(lift2(elem, lastElement.get(), eq), true);
  20944. const shouldContextToolbarHide = () => {
  20945. if (!canLaunchToolbar()) {
  20946. return true;
  20947. } else {
  20948. const contextToolbarBounds = getBounds();
  20949. const anchorBounds = is$1(lastContextPosition.get(), 'node') ? getAnchorElementBounds(editor, lastElement.get()) : getSelectionBounds(editor);
  20950. return contextToolbarBounds.height <= 0 || !isVerticalOverlap(anchorBounds, contextToolbarBounds);
  20951. }
  20952. };
  20953. const close = () => {
  20954. lastElement.clear();
  20955. lastTrigger.clear();
  20956. lastContextPosition.clear();
  20957. InlineView.hide(contextbar);
  20958. };
  20959. const hideOrRepositionIfNecessary = () => {
  20960. if (InlineView.isOpen(contextbar)) {
  20961. const contextBarEle = contextbar.element;
  20962. remove$6(contextBarEle, 'display');
  20963. if (shouldContextToolbarHide()) {
  20964. set$8(contextBarEle, 'display', 'none');
  20965. } else {
  20966. lastTrigger.set(0);
  20967. InlineView.reposition(contextbar);
  20968. }
  20969. }
  20970. };
  20971. const wrapInPopDialog = toolbarSpec => ({
  20972. dom: {
  20973. tag: 'div',
  20974. classes: ['tox-pop__dialog']
  20975. },
  20976. components: [toolbarSpec],
  20977. behaviours: derive$1([
  20978. Keying.config({ mode: 'acyclic' }),
  20979. config('pop-dialog-wrap-events', [
  20980. runOnAttached(comp => {
  20981. editor.shortcuts.add('ctrl+F9', 'focus statusbar', () => Keying.focusIn(comp));
  20982. }),
  20983. runOnDetached(_comp => {
  20984. editor.shortcuts.remove('ctrl+F9');
  20985. })
  20986. ])
  20987. ])
  20988. });
  20989. const getScopes = cached(() => categorise(registryContextToolbars, toolbarApi => {
  20990. const alloySpec = buildToolbar([toolbarApi]);
  20991. emitWith(contextbar, forwardSlideEvent, { forwardContents: wrapInPopDialog(alloySpec) });
  20992. }));
  20993. const buildContextToolbarGroups = (allButtons, ctx) => identifyButtons(editor, {
  20994. buttons: allButtons,
  20995. toolbar: ctx.items,
  20996. allowToolbarGroups: false
  20997. }, extras, Optional.some(['form:']));
  20998. const buildContextFormGroups = (ctx, providers) => ContextForm.buildInitGroups(ctx, providers);
  20999. const buildToolbar = toolbars => {
  21000. const {buttons} = editor.ui.registry.getAll();
  21001. const scopes = getScopes();
  21002. const allButtons = {
  21003. ...buttons,
  21004. ...scopes.formNavigators
  21005. };
  21006. const toolbarType = getToolbarMode(editor) === ToolbarMode$1.scrolling ? ToolbarMode$1.scrolling : ToolbarMode$1.default;
  21007. const initGroups = flatten(map$2(toolbars, ctx => ctx.type === 'contexttoolbar' ? buildContextToolbarGroups(allButtons, ctx) : buildContextFormGroups(ctx, sharedBackstage.providers)));
  21008. return renderToolbar({
  21009. type: toolbarType,
  21010. uid: generate$6('context-toolbar'),
  21011. initGroups,
  21012. onEscape: Optional.none,
  21013. cyclicKeying: true,
  21014. providers: sharedBackstage.providers
  21015. });
  21016. };
  21017. const getAnchor = (position, element) => {
  21018. const anchorage = position === 'node' ? sharedBackstage.anchors.node(element) : sharedBackstage.anchors.cursor();
  21019. const anchorLayout = getAnchorLayout(editor, position, isTouch(), {
  21020. lastElement: lastElement.get,
  21021. isReposition: () => is$1(lastTrigger.get(), 0),
  21022. getMode: () => Positioning.getMode(sink)
  21023. });
  21024. return deepMerge(anchorage, anchorLayout);
  21025. };
  21026. const launchContext = (toolbarApi, elem) => {
  21027. launchContextToolbar.cancel();
  21028. if (!canLaunchToolbar()) {
  21029. return;
  21030. }
  21031. const toolbarSpec = buildToolbar(toolbarApi);
  21032. const position = toolbarApi[0].position;
  21033. const anchor = getAnchor(position, elem);
  21034. lastContextPosition.set(position);
  21035. lastTrigger.set(1);
  21036. const contextBarEle = contextbar.element;
  21037. remove$6(contextBarEle, 'display');
  21038. if (!isSameLaunchElement(elem)) {
  21039. remove$2(contextBarEle, transitionClass);
  21040. Positioning.reset(sink, contextbar);
  21041. }
  21042. InlineView.showWithinBounds(contextbar, wrapInPopDialog(toolbarSpec), {
  21043. anchor,
  21044. transition: {
  21045. classes: [transitionClass],
  21046. mode: 'placement'
  21047. }
  21048. }, () => Optional.some(getBounds()));
  21049. elem.fold(lastElement.clear, lastElement.set);
  21050. if (shouldContextToolbarHide()) {
  21051. set$8(contextBarEle, 'display', 'none');
  21052. }
  21053. };
  21054. const launchContextToolbar = last(() => {
  21055. if (!editor.hasFocus() || editor.removed) {
  21056. return;
  21057. }
  21058. if (has(contextbar.element, transitionClass)) {
  21059. launchContextToolbar.throttle();
  21060. } else {
  21061. const scopes = getScopes();
  21062. lookup$1(scopes, editor).fold(close, info => {
  21063. launchContext(info.toolbars, Optional.some(info.elem));
  21064. });
  21065. }
  21066. }, 17);
  21067. editor.on('init', () => {
  21068. editor.on('remove', close);
  21069. editor.on('ScrollContent ScrollWindow ObjectResized ResizeEditor longpress', hideOrRepositionIfNecessary);
  21070. editor.on('click keyup focus SetContent', launchContextToolbar.throttle);
  21071. editor.on(hideContextToolbarEvent, close);
  21072. editor.on(showContextToolbarEvent, e => {
  21073. const scopes = getScopes();
  21074. get$g(scopes.lookupTable, e.toolbarKey).each(ctx => {
  21075. launchContext([ctx], someIf(e.target !== editor, e.target));
  21076. InlineView.getContent(contextbar).each(Keying.focusIn);
  21077. });
  21078. });
  21079. editor.on('focusout', _e => {
  21080. global$9.setEditorTimeout(editor, () => {
  21081. if (search(sink.element).isNone() && search(contextbar.element).isNone()) {
  21082. close();
  21083. }
  21084. }, 0);
  21085. });
  21086. editor.on('SwitchMode', () => {
  21087. if (editor.mode.isReadOnly()) {
  21088. close();
  21089. }
  21090. });
  21091. editor.on('AfterProgressState', event => {
  21092. if (event.state) {
  21093. close();
  21094. } else if (editor.hasFocus()) {
  21095. launchContextToolbar.throttle();
  21096. }
  21097. });
  21098. editor.on('NodeChange', _e => {
  21099. search(contextbar.element).fold(launchContextToolbar.throttle, noop);
  21100. });
  21101. });
  21102. };
  21103. const register$8 = editor => {
  21104. const alignToolbarButtons = [
  21105. {
  21106. name: 'alignleft',
  21107. text: 'Align left',
  21108. cmd: 'JustifyLeft',
  21109. icon: 'align-left'
  21110. },
  21111. {
  21112. name: 'aligncenter',
  21113. text: 'Align center',
  21114. cmd: 'JustifyCenter',
  21115. icon: 'align-center'
  21116. },
  21117. {
  21118. name: 'alignright',
  21119. text: 'Align right',
  21120. cmd: 'JustifyRight',
  21121. icon: 'align-right'
  21122. },
  21123. {
  21124. name: 'alignjustify',
  21125. text: 'Justify',
  21126. cmd: 'JustifyFull',
  21127. icon: 'align-justify'
  21128. }
  21129. ];
  21130. each$1(alignToolbarButtons, item => {
  21131. editor.ui.registry.addToggleButton(item.name, {
  21132. tooltip: item.text,
  21133. icon: item.icon,
  21134. onAction: onActionExecCommand(editor, item.cmd),
  21135. onSetup: onSetupFormatToggle(editor, item.name)
  21136. });
  21137. });
  21138. editor.ui.registry.addButton('alignnone', {
  21139. tooltip: 'No alignment',
  21140. icon: 'align-none',
  21141. onAction: onActionExecCommand(editor, 'JustifyNone')
  21142. });
  21143. };
  21144. const units = {
  21145. unsupportedLength: [
  21146. 'em',
  21147. 'ex',
  21148. 'cap',
  21149. 'ch',
  21150. 'ic',
  21151. 'rem',
  21152. 'lh',
  21153. 'rlh',
  21154. 'vw',
  21155. 'vh',
  21156. 'vi',
  21157. 'vb',
  21158. 'vmin',
  21159. 'vmax',
  21160. 'cm',
  21161. 'mm',
  21162. 'Q',
  21163. 'in',
  21164. 'pc',
  21165. 'pt',
  21166. 'px'
  21167. ],
  21168. fixed: [
  21169. 'px',
  21170. 'pt'
  21171. ],
  21172. relative: ['%'],
  21173. empty: ['']
  21174. };
  21175. const pattern = (() => {
  21176. const decimalDigits = '[0-9]+';
  21177. const signedInteger = '[+-]?' + decimalDigits;
  21178. const exponentPart = '[eE]' + signedInteger;
  21179. const dot = '\\.';
  21180. const opt = input => `(?:${ input })?`;
  21181. const unsignedDecimalLiteral = [
  21182. 'Infinity',
  21183. decimalDigits + dot + opt(decimalDigits) + opt(exponentPart),
  21184. dot + decimalDigits + opt(exponentPart),
  21185. decimalDigits + opt(exponentPart)
  21186. ].join('|');
  21187. const float = `[+-]?(?:${ unsignedDecimalLiteral })`;
  21188. return new RegExp(`^(${ float })(.*)$`);
  21189. })();
  21190. const isUnit = (unit, accepted) => exists(accepted, acc => exists(units[acc], check => unit === check));
  21191. const parse = (input, accepted) => {
  21192. const match = Optional.from(pattern.exec(input));
  21193. return match.bind(array => {
  21194. const value = Number(array[1]);
  21195. const unitRaw = array[2];
  21196. if (isUnit(unitRaw, accepted)) {
  21197. return Optional.some({
  21198. value,
  21199. unit: unitRaw
  21200. });
  21201. } else {
  21202. return Optional.none();
  21203. }
  21204. });
  21205. };
  21206. const normalise = (input, accepted) => parse(input, accepted).map(({value, unit}) => value + unit);
  21207. const registerController = (editor, spec) => {
  21208. const getMenuItems = () => {
  21209. const options = spec.getOptions(editor);
  21210. const initial = spec.getCurrent(editor).map(spec.hash);
  21211. const current = value$2();
  21212. return map$2(options, value => ({
  21213. type: 'togglemenuitem',
  21214. text: spec.display(value),
  21215. onSetup: api => {
  21216. const setActive = active => {
  21217. if (active) {
  21218. current.on(oldApi => oldApi.setActive(false));
  21219. current.set(api);
  21220. }
  21221. api.setActive(active);
  21222. };
  21223. setActive(is$1(initial, spec.hash(value)));
  21224. const unbindWatcher = spec.watcher(editor, value, setActive);
  21225. return () => {
  21226. current.clear();
  21227. unbindWatcher();
  21228. };
  21229. },
  21230. onAction: () => spec.setCurrent(editor, value)
  21231. }));
  21232. };
  21233. editor.ui.registry.addMenuButton(spec.name, {
  21234. tooltip: spec.text,
  21235. icon: spec.icon,
  21236. fetch: callback => callback(getMenuItems()),
  21237. onSetup: spec.onToolbarSetup
  21238. });
  21239. editor.ui.registry.addNestedMenuItem(spec.name, {
  21240. type: 'nestedmenuitem',
  21241. text: spec.text,
  21242. getSubmenuItems: getMenuItems,
  21243. onSetup: spec.onMenuSetup
  21244. });
  21245. };
  21246. const lineHeightSpec = {
  21247. name: 'lineheight',
  21248. text: 'Line height',
  21249. icon: 'line-height',
  21250. getOptions: getLineHeightFormats,
  21251. hash: input => normalise(input, [
  21252. 'fixed',
  21253. 'relative',
  21254. 'empty'
  21255. ]).getOr(input),
  21256. display: identity,
  21257. watcher: (editor, value, callback) => editor.formatter.formatChanged('lineheight', callback, false, { value }).unbind,
  21258. getCurrent: editor => Optional.from(editor.queryCommandValue('LineHeight')),
  21259. setCurrent: (editor, value) => editor.execCommand('LineHeight', false, value)
  21260. };
  21261. const languageSpec = editor => {
  21262. const settingsOpt = Optional.from(getContentLanguages(editor));
  21263. return settingsOpt.map(settings => ({
  21264. name: 'language',
  21265. text: 'Language',
  21266. icon: 'language',
  21267. getOptions: constant$1(settings),
  21268. hash: input => isUndefined(input.customCode) ? input.code : `${ input.code }/${ input.customCode }`,
  21269. display: input => input.title,
  21270. watcher: (editor, value, callback) => editor.formatter.formatChanged('lang', callback, false, {
  21271. value: value.code,
  21272. customValue: value.customCode
  21273. }).unbind,
  21274. getCurrent: editor => {
  21275. const node = SugarElement.fromDom(editor.selection.getNode());
  21276. return closest$4(node, n => Optional.some(n).filter(isElement$1).bind(ele => {
  21277. const codeOpt = getOpt(ele, 'lang');
  21278. return codeOpt.map(code => {
  21279. const customCode = getOpt(ele, 'data-mce-lang').getOrUndefined();
  21280. return {
  21281. code,
  21282. customCode,
  21283. title: ''
  21284. };
  21285. });
  21286. }));
  21287. },
  21288. setCurrent: (editor, lang) => editor.execCommand('Lang', false, lang),
  21289. onToolbarSetup: api => {
  21290. const unbinder = unbindable();
  21291. api.setActive(editor.formatter.match('lang', {}, undefined, true));
  21292. unbinder.set(editor.formatter.formatChanged('lang', api.setActive, true));
  21293. return unbinder.clear;
  21294. }
  21295. }));
  21296. };
  21297. const register$7 = editor => {
  21298. registerController(editor, lineHeightSpec);
  21299. languageSpec(editor).each(spec => registerController(editor, spec));
  21300. };
  21301. const register$6 = (editor, backstage) => {
  21302. createAlignMenu(editor, backstage);
  21303. createFontFamilyMenu(editor, backstage);
  21304. createStylesMenu(editor, backstage);
  21305. createBlocksMenu(editor, backstage);
  21306. createFontSizeMenu(editor, backstage);
  21307. };
  21308. const onSetupOutdentState = editor => onSetupEvent(editor, 'NodeChange', api => {
  21309. api.setEnabled(editor.queryCommandState('outdent'));
  21310. });
  21311. const registerButtons$2 = editor => {
  21312. editor.ui.registry.addButton('outdent', {
  21313. tooltip: 'Decrease indent',
  21314. icon: 'outdent',
  21315. onSetup: onSetupOutdentState(editor),
  21316. onAction: onActionExecCommand(editor, 'outdent')
  21317. });
  21318. editor.ui.registry.addButton('indent', {
  21319. tooltip: 'Increase indent',
  21320. icon: 'indent',
  21321. onAction: onActionExecCommand(editor, 'indent')
  21322. });
  21323. };
  21324. const register$5 = editor => {
  21325. registerButtons$2(editor);
  21326. };
  21327. const makeSetupHandler = (editor, pasteAsText) => api => {
  21328. api.setActive(pasteAsText.get());
  21329. const pastePlainTextToggleHandler = e => {
  21330. pasteAsText.set(e.state);
  21331. api.setActive(e.state);
  21332. };
  21333. editor.on('PastePlainTextToggle', pastePlainTextToggleHandler);
  21334. return () => editor.off('PastePlainTextToggle', pastePlainTextToggleHandler);
  21335. };
  21336. const register$4 = editor => {
  21337. const pasteAsText = Cell(getPasteAsText(editor));
  21338. const onAction = () => editor.execCommand('mceTogglePlainTextPaste');
  21339. editor.ui.registry.addToggleButton('pastetext', {
  21340. active: false,
  21341. icon: 'paste-text',
  21342. tooltip: 'Paste as text',
  21343. onAction,
  21344. onSetup: makeSetupHandler(editor, pasteAsText)
  21345. });
  21346. editor.ui.registry.addToggleMenuItem('pastetext', {
  21347. text: 'Paste as text',
  21348. icon: 'paste-text',
  21349. onAction,
  21350. onSetup: makeSetupHandler(editor, pasteAsText)
  21351. });
  21352. };
  21353. const onActionToggleFormat = (editor, fmt) => () => {
  21354. editor.execCommand('mceToggleFormat', false, fmt);
  21355. };
  21356. const registerFormatButtons = editor => {
  21357. global$1.each([
  21358. {
  21359. name: 'bold',
  21360. text: 'Bold',
  21361. icon: 'bold'
  21362. },
  21363. {
  21364. name: 'italic',
  21365. text: 'Italic',
  21366. icon: 'italic'
  21367. },
  21368. {
  21369. name: 'underline',
  21370. text: 'Underline',
  21371. icon: 'underline'
  21372. },
  21373. {
  21374. name: 'strikethrough',
  21375. text: 'Strikethrough',
  21376. icon: 'strike-through'
  21377. },
  21378. {
  21379. name: 'subscript',
  21380. text: 'Subscript',
  21381. icon: 'subscript'
  21382. },
  21383. {
  21384. name: 'superscript',
  21385. text: 'Superscript',
  21386. icon: 'superscript'
  21387. }
  21388. ], (btn, _idx) => {
  21389. editor.ui.registry.addToggleButton(btn.name, {
  21390. tooltip: btn.text,
  21391. icon: btn.icon,
  21392. onSetup: onSetupFormatToggle(editor, btn.name),
  21393. onAction: onActionToggleFormat(editor, btn.name)
  21394. });
  21395. });
  21396. for (let i = 1; i <= 6; i++) {
  21397. const name = 'h' + i;
  21398. editor.ui.registry.addToggleButton(name, {
  21399. text: name.toUpperCase(),
  21400. tooltip: 'Heading ' + i,
  21401. onSetup: onSetupFormatToggle(editor, name),
  21402. onAction: onActionToggleFormat(editor, name)
  21403. });
  21404. }
  21405. };
  21406. const registerCommandButtons = editor => {
  21407. global$1.each([
  21408. {
  21409. name: 'cut',
  21410. text: 'Cut',
  21411. action: 'Cut',
  21412. icon: 'cut'
  21413. },
  21414. {
  21415. name: 'copy',
  21416. text: 'Copy',
  21417. action: 'Copy',
  21418. icon: 'copy'
  21419. },
  21420. {
  21421. name: 'paste',
  21422. text: 'Paste',
  21423. action: 'Paste',
  21424. icon: 'paste'
  21425. },
  21426. {
  21427. name: 'help',
  21428. text: 'Help',
  21429. action: 'mceHelp',
  21430. icon: 'help'
  21431. },
  21432. {
  21433. name: 'selectall',
  21434. text: 'Select all',
  21435. action: 'SelectAll',
  21436. icon: 'select-all'
  21437. },
  21438. {
  21439. name: 'newdocument',
  21440. text: 'New document',
  21441. action: 'mceNewDocument',
  21442. icon: 'new-document'
  21443. },
  21444. {
  21445. name: 'removeformat',
  21446. text: 'Clear formatting',
  21447. action: 'RemoveFormat',
  21448. icon: 'remove-formatting'
  21449. },
  21450. {
  21451. name: 'remove',
  21452. text: 'Remove',
  21453. action: 'Delete',
  21454. icon: 'remove'
  21455. },
  21456. {
  21457. name: 'print',
  21458. text: 'Print',
  21459. action: 'mcePrint',
  21460. icon: 'print'
  21461. },
  21462. {
  21463. name: 'hr',
  21464. text: 'Horizontal line',
  21465. action: 'InsertHorizontalRule',
  21466. icon: 'horizontal-rule'
  21467. }
  21468. ], btn => {
  21469. editor.ui.registry.addButton(btn.name, {
  21470. tooltip: btn.text,
  21471. icon: btn.icon,
  21472. onAction: onActionExecCommand(editor, btn.action)
  21473. });
  21474. });
  21475. };
  21476. const registerCommandToggleButtons = editor => {
  21477. global$1.each([{
  21478. name: 'blockquote',
  21479. text: 'Blockquote',
  21480. action: 'mceBlockQuote',
  21481. icon: 'quote'
  21482. }], btn => {
  21483. editor.ui.registry.addToggleButton(btn.name, {
  21484. tooltip: btn.text,
  21485. icon: btn.icon,
  21486. onAction: onActionExecCommand(editor, btn.action),
  21487. onSetup: onSetupFormatToggle(editor, btn.name)
  21488. });
  21489. });
  21490. };
  21491. const registerButtons$1 = editor => {
  21492. registerFormatButtons(editor);
  21493. registerCommandButtons(editor);
  21494. registerCommandToggleButtons(editor);
  21495. };
  21496. const registerMenuItems$2 = editor => {
  21497. global$1.each([
  21498. {
  21499. name: 'bold',
  21500. text: 'Bold',
  21501. action: 'Bold',
  21502. icon: 'bold',
  21503. shortcut: 'Meta+B'
  21504. },
  21505. {
  21506. name: 'italic',
  21507. text: 'Italic',
  21508. action: 'Italic',
  21509. icon: 'italic',
  21510. shortcut: 'Meta+I'
  21511. },
  21512. {
  21513. name: 'underline',
  21514. text: 'Underline',
  21515. action: 'Underline',
  21516. icon: 'underline',
  21517. shortcut: 'Meta+U'
  21518. },
  21519. {
  21520. name: 'strikethrough',
  21521. text: 'Strikethrough',
  21522. action: 'Strikethrough',
  21523. icon: 'strike-through'
  21524. },
  21525. {
  21526. name: 'subscript',
  21527. text: 'Subscript',
  21528. action: 'Subscript',
  21529. icon: 'subscript'
  21530. },
  21531. {
  21532. name: 'superscript',
  21533. text: 'Superscript',
  21534. action: 'Superscript',
  21535. icon: 'superscript'
  21536. },
  21537. {
  21538. name: 'removeformat',
  21539. text: 'Clear formatting',
  21540. action: 'RemoveFormat',
  21541. icon: 'remove-formatting'
  21542. },
  21543. {
  21544. name: 'newdocument',
  21545. text: 'New document',
  21546. action: 'mceNewDocument',
  21547. icon: 'new-document'
  21548. },
  21549. {
  21550. name: 'cut',
  21551. text: 'Cut',
  21552. action: 'Cut',
  21553. icon: 'cut',
  21554. shortcut: 'Meta+X'
  21555. },
  21556. {
  21557. name: 'copy',
  21558. text: 'Copy',
  21559. action: 'Copy',
  21560. icon: 'copy',
  21561. shortcut: 'Meta+C'
  21562. },
  21563. {
  21564. name: 'paste',
  21565. text: 'Paste',
  21566. action: 'Paste',
  21567. icon: 'paste',
  21568. shortcut: 'Meta+V'
  21569. },
  21570. {
  21571. name: 'selectall',
  21572. text: 'Select all',
  21573. action: 'SelectAll',
  21574. icon: 'select-all',
  21575. shortcut: 'Meta+A'
  21576. },
  21577. {
  21578. name: 'print',
  21579. text: 'Print...',
  21580. action: 'mcePrint',
  21581. icon: 'print',
  21582. shortcut: 'Meta+P'
  21583. },
  21584. {
  21585. name: 'hr',
  21586. text: 'Horizontal line',
  21587. action: 'InsertHorizontalRule',
  21588. icon: 'horizontal-rule'
  21589. }
  21590. ], menuitem => {
  21591. editor.ui.registry.addMenuItem(menuitem.name, {
  21592. text: menuitem.text,
  21593. icon: menuitem.icon,
  21594. shortcut: menuitem.shortcut,
  21595. onAction: onActionExecCommand(editor, menuitem.action)
  21596. });
  21597. });
  21598. editor.ui.registry.addMenuItem('codeformat', {
  21599. text: 'Code',
  21600. icon: 'sourcecode',
  21601. onAction: onActionToggleFormat(editor, 'code')
  21602. });
  21603. };
  21604. const register$3 = editor => {
  21605. registerButtons$1(editor);
  21606. registerMenuItems$2(editor);
  21607. };
  21608. const onSetupUndoRedoState = (editor, type) => onSetupEvent(editor, 'Undo Redo AddUndo TypingUndo ClearUndos SwitchMode', api => {
  21609. api.setEnabled(!editor.mode.isReadOnly() && editor.undoManager[type]());
  21610. });
  21611. const registerMenuItems$1 = editor => {
  21612. editor.ui.registry.addMenuItem('undo', {
  21613. text: 'Undo',
  21614. icon: 'undo',
  21615. shortcut: 'Meta+Z',
  21616. onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
  21617. onAction: onActionExecCommand(editor, 'undo')
  21618. });
  21619. editor.ui.registry.addMenuItem('redo', {
  21620. text: 'Redo',
  21621. icon: 'redo',
  21622. shortcut: 'Meta+Y',
  21623. onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
  21624. onAction: onActionExecCommand(editor, 'redo')
  21625. });
  21626. };
  21627. const registerButtons = editor => {
  21628. editor.ui.registry.addButton('undo', {
  21629. tooltip: 'Undo',
  21630. icon: 'undo',
  21631. enabled: false,
  21632. onSetup: onSetupUndoRedoState(editor, 'hasUndo'),
  21633. onAction: onActionExecCommand(editor, 'undo')
  21634. });
  21635. editor.ui.registry.addButton('redo', {
  21636. tooltip: 'Redo',
  21637. icon: 'redo',
  21638. enabled: false,
  21639. onSetup: onSetupUndoRedoState(editor, 'hasRedo'),
  21640. onAction: onActionExecCommand(editor, 'redo')
  21641. });
  21642. };
  21643. const register$2 = editor => {
  21644. registerMenuItems$1(editor);
  21645. registerButtons(editor);
  21646. };
  21647. const onSetupVisualAidState = editor => onSetupEvent(editor, 'VisualAid', api => {
  21648. api.setActive(editor.hasVisual);
  21649. });
  21650. const registerMenuItems = editor => {
  21651. editor.ui.registry.addToggleMenuItem('visualaid', {
  21652. text: 'Visual aids',
  21653. onSetup: onSetupVisualAidState(editor),
  21654. onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
  21655. });
  21656. };
  21657. const registerToolbarButton = editor => {
  21658. editor.ui.registry.addButton('visualaid', {
  21659. tooltip: 'Visual aids',
  21660. text: 'Visual aids',
  21661. onAction: onActionExecCommand(editor, 'mceToggleVisualAid')
  21662. });
  21663. };
  21664. const register$1 = editor => {
  21665. registerToolbarButton(editor);
  21666. registerMenuItems(editor);
  21667. };
  21668. const setup$6 = (editor, backstage) => {
  21669. register$8(editor);
  21670. register$3(editor);
  21671. register$6(editor, backstage);
  21672. register$2(editor);
  21673. register$c(editor);
  21674. register$1(editor);
  21675. register$5(editor);
  21676. register$7(editor);
  21677. register$4(editor);
  21678. };
  21679. const patchPipeConfig = config => isString(config) ? config.split(/[ ,]/) : config;
  21680. const option = name => editor => editor.options.get(name);
  21681. const register = editor => {
  21682. const registerOption = editor.options.register;
  21683. registerOption('contextmenu_avoid_overlap', {
  21684. processor: 'string',
  21685. default: ''
  21686. });
  21687. registerOption('contextmenu_never_use_native', {
  21688. processor: 'boolean',
  21689. default: false
  21690. });
  21691. registerOption('contextmenu', {
  21692. processor: value => {
  21693. if (value === false) {
  21694. return {
  21695. value: [],
  21696. valid: true
  21697. };
  21698. } else if (isString(value) || isArrayOf(value, isString)) {
  21699. return {
  21700. value: patchPipeConfig(value),
  21701. valid: true
  21702. };
  21703. } else {
  21704. return {
  21705. valid: false,
  21706. message: 'Must be false or a string.'
  21707. };
  21708. }
  21709. },
  21710. default: 'link linkchecker image editimage table spellchecker configurepermanentpen'
  21711. });
  21712. };
  21713. const shouldNeverUseNative = option('contextmenu_never_use_native');
  21714. const getAvoidOverlapSelector = option('contextmenu_avoid_overlap');
  21715. const isContextMenuDisabled = editor => getContextMenu(editor).length === 0;
  21716. const getContextMenu = editor => {
  21717. const contextMenus = editor.ui.registry.getAll().contextMenus;
  21718. const contextMenu = editor.options.get('contextmenu');
  21719. if (editor.options.isSet('contextmenu')) {
  21720. return contextMenu;
  21721. } else {
  21722. return filter$2(contextMenu, item => has$2(contextMenus, item));
  21723. }
  21724. };
  21725. const nu = (x, y) => ({
  21726. type: 'makeshift',
  21727. x,
  21728. y
  21729. });
  21730. const transpose = (pos, dx, dy) => {
  21731. return nu(pos.x + dx, pos.y + dy);
  21732. };
  21733. const isTouchEvent = e => e.type === 'longpress' || e.type.indexOf('touch') === 0;
  21734. const fromPageXY = e => {
  21735. if (isTouchEvent(e)) {
  21736. const touch = e.touches[0];
  21737. return nu(touch.pageX, touch.pageY);
  21738. } else {
  21739. return nu(e.pageX, e.pageY);
  21740. }
  21741. };
  21742. const fromClientXY = e => {
  21743. if (isTouchEvent(e)) {
  21744. const touch = e.touches[0];
  21745. return nu(touch.clientX, touch.clientY);
  21746. } else {
  21747. return nu(e.clientX, e.clientY);
  21748. }
  21749. };
  21750. const transposeContentAreaContainer = (element, pos) => {
  21751. const containerPos = global$7.DOM.getPos(element);
  21752. return transpose(pos, containerPos.x, containerPos.y);
  21753. };
  21754. const getPointAnchor = (editor, e) => {
  21755. if (e.type === 'contextmenu' || e.type === 'longpress') {
  21756. if (editor.inline) {
  21757. return fromPageXY(e);
  21758. } else {
  21759. return transposeContentAreaContainer(editor.getContentAreaContainer(), fromClientXY(e));
  21760. }
  21761. } else {
  21762. return getSelectionAnchor(editor);
  21763. }
  21764. };
  21765. const getSelectionAnchor = editor => {
  21766. return {
  21767. type: 'selection',
  21768. root: SugarElement.fromDom(editor.selection.getNode())
  21769. };
  21770. };
  21771. const getNodeAnchor = editor => ({
  21772. type: 'node',
  21773. node: Optional.some(SugarElement.fromDom(editor.selection.getNode())),
  21774. root: SugarElement.fromDom(editor.getBody())
  21775. });
  21776. const getAnchorSpec$1 = (editor, e, anchorType) => {
  21777. switch (anchorType) {
  21778. case 'node':
  21779. return getNodeAnchor(editor);
  21780. case 'point':
  21781. return getPointAnchor(editor, e);
  21782. case 'selection':
  21783. return getSelectionAnchor(editor);
  21784. }
  21785. };
  21786. const initAndShow$1 = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
  21787. const items = buildMenu();
  21788. const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
  21789. build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, false).map(menuData => {
  21790. e.preventDefault();
  21791. InlineView.showMenuAt(contextmenu, { anchor: anchorSpec }, {
  21792. menu: { markers: markers('normal') },
  21793. data: menuData
  21794. });
  21795. });
  21796. };
  21797. const layouts = {
  21798. onLtr: () => [
  21799. south$2,
  21800. southeast$2,
  21801. southwest$2,
  21802. northeast$2,
  21803. northwest$2,
  21804. north$2,
  21805. north,
  21806. south,
  21807. northeast,
  21808. southeast,
  21809. northwest,
  21810. southwest
  21811. ],
  21812. onRtl: () => [
  21813. south$2,
  21814. southwest$2,
  21815. southeast$2,
  21816. northwest$2,
  21817. northeast$2,
  21818. north$2,
  21819. north,
  21820. south,
  21821. northwest,
  21822. southwest,
  21823. northeast,
  21824. southeast
  21825. ]
  21826. };
  21827. const bubbleSize = 12;
  21828. const bubbleAlignments = {
  21829. valignCentre: [],
  21830. alignCentre: [],
  21831. alignLeft: ['tox-pop--align-left'],
  21832. alignRight: ['tox-pop--align-right'],
  21833. right: ['tox-pop--right'],
  21834. left: ['tox-pop--left'],
  21835. bottom: ['tox-pop--bottom'],
  21836. top: ['tox-pop--top']
  21837. };
  21838. const isTouchWithinSelection = (editor, e) => {
  21839. const selection = editor.selection;
  21840. if (selection.isCollapsed() || e.touches.length < 1) {
  21841. return false;
  21842. } else {
  21843. const touch = e.touches[0];
  21844. const rng = selection.getRng();
  21845. const rngRectOpt = getFirstRect(editor.getWin(), SimSelection.domRange(rng));
  21846. return rngRectOpt.exists(rngRect => rngRect.left <= touch.clientX && rngRect.right >= touch.clientX && rngRect.top <= touch.clientY && rngRect.bottom >= touch.clientY);
  21847. }
  21848. };
  21849. const setupiOSOverrides = editor => {
  21850. const originalSelection = editor.selection.getRng();
  21851. const selectionReset = () => {
  21852. global$9.setEditorTimeout(editor, () => {
  21853. editor.selection.setRng(originalSelection);
  21854. }, 10);
  21855. unbindEventListeners();
  21856. };
  21857. editor.once('touchend', selectionReset);
  21858. const preventMousedown = e => {
  21859. e.preventDefault();
  21860. e.stopImmediatePropagation();
  21861. };
  21862. editor.on('mousedown', preventMousedown, true);
  21863. const clearSelectionReset = () => unbindEventListeners();
  21864. editor.once('longpresscancel', clearSelectionReset);
  21865. const unbindEventListeners = () => {
  21866. editor.off('touchend', selectionReset);
  21867. editor.off('longpresscancel', clearSelectionReset);
  21868. editor.off('mousedown', preventMousedown);
  21869. };
  21870. };
  21871. const getAnchorSpec = (editor, e, anchorType) => {
  21872. const anchorSpec = getAnchorSpec$1(editor, e, anchorType);
  21873. const bubbleYOffset = anchorType === 'point' ? bubbleSize : 0;
  21874. return {
  21875. bubble: nu$5(0, bubbleYOffset, bubbleAlignments),
  21876. layouts,
  21877. overrides: {
  21878. maxWidthFunction: expandable(),
  21879. maxHeightFunction: expandable$1()
  21880. },
  21881. ...anchorSpec
  21882. };
  21883. };
  21884. const show = (editor, e, items, backstage, contextmenu, anchorType, highlightImmediately) => {
  21885. const anchorSpec = getAnchorSpec(editor, e, anchorType);
  21886. build(items, ItemResponse$1.CLOSE_ON_EXECUTE, backstage, true).map(menuData => {
  21887. e.preventDefault();
  21888. InlineView.showMenuWithinBounds(contextmenu, { anchor: anchorSpec }, {
  21889. menu: {
  21890. markers: markers('normal'),
  21891. highlightImmediately
  21892. },
  21893. data: menuData,
  21894. type: 'horizontal'
  21895. }, () => Optional.some(getContextToolbarBounds(editor, backstage.shared, anchorType === 'node' ? 'node' : 'selection')));
  21896. editor.dispatch(hideContextToolbarEvent);
  21897. });
  21898. };
  21899. const initAndShow = (editor, e, buildMenu, backstage, contextmenu, anchorType) => {
  21900. const detection = detect$1();
  21901. const isiOS = detection.os.isiOS();
  21902. const isMacOS = detection.os.isMacOS();
  21903. const isAndroid = detection.os.isAndroid();
  21904. const isTouch = detection.deviceType.isTouch();
  21905. const shouldHighlightImmediately = () => !(isAndroid || isiOS || isMacOS && isTouch);
  21906. const open = () => {
  21907. const items = buildMenu();
  21908. show(editor, e, items, backstage, contextmenu, anchorType, shouldHighlightImmediately());
  21909. };
  21910. if ((isMacOS || isiOS) && anchorType !== 'node') {
  21911. const openiOS = () => {
  21912. setupiOSOverrides(editor);
  21913. open();
  21914. };
  21915. if (isTouchWithinSelection(editor, e)) {
  21916. openiOS();
  21917. } else {
  21918. editor.once('selectionchange', openiOS);
  21919. editor.once('touchend', () => editor.off('selectionchange', openiOS));
  21920. }
  21921. } else {
  21922. open();
  21923. }
  21924. };
  21925. const isSeparator = item => isString(item) ? item === '|' : item.type === 'separator';
  21926. const separator = { type: 'separator' };
  21927. const makeContextItem = item => {
  21928. const commonMenuItem = item => ({
  21929. text: item.text,
  21930. icon: item.icon,
  21931. enabled: item.enabled,
  21932. shortcut: item.shortcut
  21933. });
  21934. if (isString(item)) {
  21935. return item;
  21936. } else {
  21937. switch (item.type) {
  21938. case 'separator':
  21939. return separator;
  21940. case 'submenu':
  21941. return {
  21942. type: 'nestedmenuitem',
  21943. ...commonMenuItem(item),
  21944. getSubmenuItems: () => {
  21945. const items = item.getSubmenuItems();
  21946. if (isString(items)) {
  21947. return items;
  21948. } else {
  21949. return map$2(items, makeContextItem);
  21950. }
  21951. }
  21952. };
  21953. default:
  21954. return {
  21955. type: 'menuitem',
  21956. ...commonMenuItem(item),
  21957. onAction: noarg(item.onAction)
  21958. };
  21959. }
  21960. }
  21961. };
  21962. const addContextMenuGroup = (xs, groupItems) => {
  21963. if (groupItems.length === 0) {
  21964. return xs;
  21965. }
  21966. const lastMenuItem = last$1(xs).filter(item => !isSeparator(item));
  21967. const before = lastMenuItem.fold(() => [], _ => [separator]);
  21968. return xs.concat(before).concat(groupItems).concat([separator]);
  21969. };
  21970. const generateContextMenu = (contextMenus, menuConfig, selectedElement) => {
  21971. const sections = foldl(menuConfig, (acc, name) => {
  21972. return get$g(contextMenus, name.toLowerCase()).map(menu => {
  21973. const items = menu.update(selectedElement);
  21974. if (isString(items)) {
  21975. return addContextMenuGroup(acc, items.split(' '));
  21976. } else if (items.length > 0) {
  21977. const allItems = map$2(items, makeContextItem);
  21978. return addContextMenuGroup(acc, allItems);
  21979. } else {
  21980. return acc;
  21981. }
  21982. }).getOrThunk(() => acc.concat([name]));
  21983. }, []);
  21984. if (sections.length > 0 && isSeparator(sections[sections.length - 1])) {
  21985. sections.pop();
  21986. }
  21987. return sections;
  21988. };
  21989. const isNativeOverrideKeyEvent = (editor, e) => e.ctrlKey && !shouldNeverUseNative(editor);
  21990. const isTriggeredByKeyboard = (editor, e) => e.type !== 'longpress' && (e.button !== 2 || e.target === editor.getBody() && e.pointerType === '');
  21991. const getSelectedElement = (editor, e) => isTriggeredByKeyboard(editor, e) ? editor.selection.getStart(true) : e.target;
  21992. const getAnchorType = (editor, e) => {
  21993. const selector = getAvoidOverlapSelector(editor);
  21994. const anchorType = isTriggeredByKeyboard(editor, e) ? 'selection' : 'point';
  21995. if (isNotEmpty(selector)) {
  21996. const target = getSelectedElement(editor, e);
  21997. const selectorExists = closest(SugarElement.fromDom(target), selector);
  21998. return selectorExists ? 'node' : anchorType;
  21999. } else {
  22000. return anchorType;
  22001. }
  22002. };
  22003. const setup$5 = (editor, lazySink, backstage) => {
  22004. const detection = detect$1();
  22005. const isTouch = detection.deviceType.isTouch;
  22006. const contextmenu = build$1(InlineView.sketch({
  22007. dom: { tag: 'div' },
  22008. lazySink,
  22009. onEscape: () => editor.focus(),
  22010. onShow: () => backstage.setContextMenuState(true),
  22011. onHide: () => backstage.setContextMenuState(false),
  22012. fireDismissalEventInstead: {},
  22013. inlineBehaviours: derive$1([config('dismissContextMenu', [run$1(dismissRequested(), (comp, _se) => {
  22014. Sandboxing.close(comp);
  22015. editor.focus();
  22016. })])])
  22017. }));
  22018. const hideContextMenu = _e => InlineView.hide(contextmenu);
  22019. const showContextMenu = e => {
  22020. if (shouldNeverUseNative(editor)) {
  22021. e.preventDefault();
  22022. }
  22023. if (isNativeOverrideKeyEvent(editor, e) || isContextMenuDisabled(editor)) {
  22024. return;
  22025. }
  22026. const anchorType = getAnchorType(editor, e);
  22027. const buildMenu = () => {
  22028. const selectedElement = getSelectedElement(editor, e);
  22029. const registry = editor.ui.registry.getAll();
  22030. const menuConfig = getContextMenu(editor);
  22031. return generateContextMenu(registry.contextMenus, menuConfig, selectedElement);
  22032. };
  22033. const initAndShow$2 = isTouch() ? initAndShow : initAndShow$1;
  22034. initAndShow$2(editor, e, buildMenu, backstage, contextmenu, anchorType);
  22035. };
  22036. editor.on('init', () => {
  22037. const hideEvents = 'ResizeEditor ScrollContent ScrollWindow longpresscancel' + (isTouch() ? '' : ' ResizeWindow');
  22038. editor.on(hideEvents, hideContextMenu);
  22039. editor.on('longpress contextmenu', showContextMenu);
  22040. });
  22041. };
  22042. const adt = Adt.generate([
  22043. {
  22044. offset: [
  22045. 'x',
  22046. 'y'
  22047. ]
  22048. },
  22049. {
  22050. absolute: [
  22051. 'x',
  22052. 'y'
  22053. ]
  22054. },
  22055. {
  22056. fixed: [
  22057. 'x',
  22058. 'y'
  22059. ]
  22060. }
  22061. ]);
  22062. const subtract = change => point => point.translate(-change.left, -change.top);
  22063. const add = change => point => point.translate(change.left, change.top);
  22064. const transform = changes => (x, y) => foldl(changes, (rest, f) => f(rest), SugarPosition(x, y));
  22065. const asFixed = (coord, scroll, origin) => coord.fold(transform([
  22066. add(origin),
  22067. subtract(scroll)
  22068. ]), transform([subtract(scroll)]), transform([]));
  22069. const asAbsolute = (coord, scroll, origin) => coord.fold(transform([add(origin)]), transform([]), transform([add(scroll)]));
  22070. const asOffset = (coord, scroll, origin) => coord.fold(transform([]), transform([subtract(origin)]), transform([
  22071. add(scroll),
  22072. subtract(origin)
  22073. ]));
  22074. const withinRange = (coord1, coord2, xRange, yRange, scroll, origin) => {
  22075. const a1 = asAbsolute(coord1, scroll, origin);
  22076. const a2 = asAbsolute(coord2, scroll, origin);
  22077. return Math.abs(a1.left - a2.left) <= xRange && Math.abs(a1.top - a2.top) <= yRange;
  22078. };
  22079. const getDeltas = (coord1, coord2, xRange, yRange, scroll, origin) => {
  22080. const a1 = asAbsolute(coord1, scroll, origin);
  22081. const a2 = asAbsolute(coord2, scroll, origin);
  22082. const left = Math.abs(a1.left - a2.left);
  22083. const top = Math.abs(a1.top - a2.top);
  22084. return SugarPosition(left, top);
  22085. };
  22086. const toStyles = (coord, scroll, origin) => {
  22087. const stylesOpt = coord.fold((x, y) => ({
  22088. position: Optional.some('absolute'),
  22089. left: Optional.some(x + 'px'),
  22090. top: Optional.some(y + 'px')
  22091. }), (x, y) => ({
  22092. position: Optional.some('absolute'),
  22093. left: Optional.some(x - origin.left + 'px'),
  22094. top: Optional.some(y - origin.top + 'px')
  22095. }), (x, y) => ({
  22096. position: Optional.some('fixed'),
  22097. left: Optional.some(x + 'px'),
  22098. top: Optional.some(y + 'px')
  22099. }));
  22100. return {
  22101. right: Optional.none(),
  22102. bottom: Optional.none(),
  22103. ...stylesOpt
  22104. };
  22105. };
  22106. 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));
  22107. const absorb = (partialCoord, originalCoord, scroll, origin) => {
  22108. const absorbOne = (stencil, nu) => (optX, optY) => {
  22109. const original = stencil(originalCoord, scroll, origin);
  22110. return nu(optX.getOr(original.left), optY.getOr(original.top));
  22111. };
  22112. return partialCoord.fold(absorbOne(asOffset, offset), absorbOne(asAbsolute, absolute), absorbOne(asFixed, fixed));
  22113. };
  22114. const offset = adt.offset;
  22115. const absolute = adt.absolute;
  22116. const fixed = adt.fixed;
  22117. const parseAttrToInt = (element, name) => {
  22118. const value = get$f(element, name);
  22119. return isUndefined(value) ? NaN : parseInt(value, 10);
  22120. };
  22121. const get = (component, snapsInfo) => {
  22122. const element = component.element;
  22123. const x = parseAttrToInt(element, snapsInfo.leftAttr);
  22124. const y = parseAttrToInt(element, snapsInfo.topAttr);
  22125. return isNaN(x) || isNaN(y) ? Optional.none() : Optional.some(SugarPosition(x, y));
  22126. };
  22127. const set = (component, snapsInfo, pt) => {
  22128. const element = component.element;
  22129. set$9(element, snapsInfo.leftAttr, pt.left + 'px');
  22130. set$9(element, snapsInfo.topAttr, pt.top + 'px');
  22131. };
  22132. const clear = (component, snapsInfo) => {
  22133. const element = component.element;
  22134. remove$7(element, snapsInfo.leftAttr);
  22135. remove$7(element, snapsInfo.topAttr);
  22136. };
  22137. const getCoords = (component, snapInfo, coord, delta) => get(component, snapInfo).fold(() => coord, fixed$1 => fixed(fixed$1.left + delta.left, fixed$1.top + delta.top));
  22138. const moveOrSnap = (component, snapInfo, coord, delta, scroll, origin) => {
  22139. const newCoord = getCoords(component, snapInfo, coord, delta);
  22140. const snap = snapInfo.mustSnap ? findClosestSnap(component, snapInfo, newCoord, scroll, origin) : findSnap(component, snapInfo, newCoord, scroll, origin);
  22141. const fixedCoord = asFixed(newCoord, scroll, origin);
  22142. set(component, snapInfo, fixedCoord);
  22143. return snap.fold(() => ({
  22144. coord: fixed(fixedCoord.left, fixedCoord.top),
  22145. extra: Optional.none()
  22146. }), spanned => ({
  22147. coord: spanned.output,
  22148. extra: spanned.extra
  22149. }));
  22150. };
  22151. const stopDrag = (component, snapInfo) => {
  22152. clear(component, snapInfo);
  22153. };
  22154. const findMatchingSnap = (snaps, newCoord, scroll, origin) => findMap(snaps, snap => {
  22155. const sensor = snap.sensor;
  22156. const inRange = withinRange(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
  22157. return inRange ? Optional.some({
  22158. output: absorb(snap.output, newCoord, scroll, origin),
  22159. extra: snap.extra
  22160. }) : Optional.none();
  22161. });
  22162. const findClosestSnap = (component, snapInfo, newCoord, scroll, origin) => {
  22163. const snaps = snapInfo.getSnapPoints(component);
  22164. const matchSnap = findMatchingSnap(snaps, newCoord, scroll, origin);
  22165. return matchSnap.orThunk(() => {
  22166. const bestSnap = foldl(snaps, (acc, snap) => {
  22167. const sensor = snap.sensor;
  22168. const deltas = getDeltas(newCoord, sensor, snap.range.left, snap.range.top, scroll, origin);
  22169. return acc.deltas.fold(() => ({
  22170. deltas: Optional.some(deltas),
  22171. snap: Optional.some(snap)
  22172. }), bestDeltas => {
  22173. const currAvg = (deltas.left + deltas.top) / 2;
  22174. const bestAvg = (bestDeltas.left + bestDeltas.top) / 2;
  22175. if (currAvg <= bestAvg) {
  22176. return {
  22177. deltas: Optional.some(deltas),
  22178. snap: Optional.some(snap)
  22179. };
  22180. } else {
  22181. return acc;
  22182. }
  22183. });
  22184. }, {
  22185. deltas: Optional.none(),
  22186. snap: Optional.none()
  22187. });
  22188. return bestSnap.snap.map(snap => ({
  22189. output: absorb(snap.output, newCoord, scroll, origin),
  22190. extra: snap.extra
  22191. }));
  22192. });
  22193. };
  22194. const findSnap = (component, snapInfo, newCoord, scroll, origin) => {
  22195. const snaps = snapInfo.getSnapPoints(component);
  22196. return findMatchingSnap(snaps, newCoord, scroll, origin);
  22197. };
  22198. const snapTo$1 = (snap, scroll, origin) => ({
  22199. coord: absorb(snap.output, snap.output, scroll, origin),
  22200. extra: snap.extra
  22201. });
  22202. const snapTo = (component, dragConfig, _state, snap) => {
  22203. const target = dragConfig.getTarget(component.element);
  22204. if (dragConfig.repositionTarget) {
  22205. const doc = owner$4(component.element);
  22206. const scroll = get$b(doc);
  22207. const origin = getOrigin(target);
  22208. const snapPin = snapTo$1(snap, scroll, origin);
  22209. const styles = toStyles(snapPin.coord, scroll, origin);
  22210. setOptions(target, styles);
  22211. }
  22212. };
  22213. var DraggingApis = /*#__PURE__*/Object.freeze({
  22214. __proto__: null,
  22215. snapTo: snapTo
  22216. });
  22217. const initialAttribute = 'data-initial-z-index';
  22218. const resetZIndex = blocker => {
  22219. parent(blocker.element).filter(isElement$1).each(root => {
  22220. getOpt(root, initialAttribute).fold(() => remove$6(root, 'z-index'), zIndex => set$8(root, 'z-index', zIndex));
  22221. remove$7(root, initialAttribute);
  22222. });
  22223. };
  22224. const changeZIndex = blocker => {
  22225. parent(blocker.element).filter(isElement$1).each(root => {
  22226. getRaw(root, 'z-index').each(zindex => {
  22227. set$9(root, initialAttribute, zindex);
  22228. });
  22229. set$8(root, 'z-index', get$e(blocker.element, 'z-index'));
  22230. });
  22231. };
  22232. const instigate = (anyComponent, blocker) => {
  22233. anyComponent.getSystem().addToGui(blocker);
  22234. changeZIndex(blocker);
  22235. };
  22236. const discard = blocker => {
  22237. resetZIndex(blocker);
  22238. blocker.getSystem().removeFromGui(blocker);
  22239. };
  22240. const createComponent = (component, blockerClass, blockerEvents) => component.getSystem().build(Container.sketch({
  22241. dom: {
  22242. styles: {
  22243. 'left': '0px',
  22244. 'top': '0px',
  22245. 'width': '100%',
  22246. 'height': '100%',
  22247. 'position': 'fixed',
  22248. 'z-index': '1000000000000000'
  22249. },
  22250. classes: [blockerClass]
  22251. },
  22252. events: blockerEvents
  22253. }));
  22254. var SnapSchema = optionObjOf('snaps', [
  22255. required$1('getSnapPoints'),
  22256. onHandler('onSensor'),
  22257. required$1('leftAttr'),
  22258. required$1('topAttr'),
  22259. defaulted('lazyViewport', win),
  22260. defaulted('mustSnap', false)
  22261. ]);
  22262. const schema$6 = [
  22263. defaulted('useFixed', never),
  22264. required$1('blockerClass'),
  22265. defaulted('getTarget', identity),
  22266. defaulted('onDrag', noop),
  22267. defaulted('repositionTarget', true),
  22268. defaulted('onDrop', noop),
  22269. defaultedFunction('getBounds', win),
  22270. SnapSchema
  22271. ];
  22272. const getCurrentCoord = target => lift3(getRaw(target, 'left'), getRaw(target, 'top'), getRaw(target, 'position'), (left, top, position) => {
  22273. const nu = position === 'fixed' ? fixed : offset;
  22274. return nu(parseInt(left, 10), parseInt(top, 10));
  22275. }).getOrThunk(() => {
  22276. const location = absolute$3(target);
  22277. return absolute(location.left, location.top);
  22278. });
  22279. const clampCoords = (component, coords, scroll, origin, startData) => {
  22280. const bounds = startData.bounds;
  22281. const absoluteCoord = asAbsolute(coords, scroll, origin);
  22282. const newX = clamp(absoluteCoord.left, bounds.x, bounds.x + bounds.width - startData.width);
  22283. const newY = clamp(absoluteCoord.top, bounds.y, bounds.y + bounds.height - startData.height);
  22284. const newCoords = absolute(newX, newY);
  22285. return coords.fold(() => {
  22286. const offset$1 = asOffset(newCoords, scroll, origin);
  22287. return offset(offset$1.left, offset$1.top);
  22288. }, constant$1(newCoords), () => {
  22289. const fixed$1 = asFixed(newCoords, scroll, origin);
  22290. return fixed(fixed$1.left, fixed$1.top);
  22291. });
  22292. };
  22293. const calcNewCoord = (component, optSnaps, currentCoord, scroll, origin, delta, startData) => {
  22294. const newCoord = optSnaps.fold(() => {
  22295. const translated = translate(currentCoord, delta.left, delta.top);
  22296. const fixedCoord = asFixed(translated, scroll, origin);
  22297. return fixed(fixedCoord.left, fixedCoord.top);
  22298. }, snapInfo => {
  22299. const snapping = moveOrSnap(component, snapInfo, currentCoord, delta, scroll, origin);
  22300. snapping.extra.each(extra => {
  22301. snapInfo.onSensor(component, extra);
  22302. });
  22303. return snapping.coord;
  22304. });
  22305. return clampCoords(component, newCoord, scroll, origin, startData);
  22306. };
  22307. const dragBy = (component, dragConfig, startData, delta) => {
  22308. const target = dragConfig.getTarget(component.element);
  22309. if (dragConfig.repositionTarget) {
  22310. const doc = owner$4(component.element);
  22311. const scroll = get$b(doc);
  22312. const origin = getOrigin(target);
  22313. const currentCoord = getCurrentCoord(target);
  22314. const newCoord = calcNewCoord(component, dragConfig.snaps, currentCoord, scroll, origin, delta, startData);
  22315. const styles = toStyles(newCoord, scroll, origin);
  22316. setOptions(target, styles);
  22317. }
  22318. dragConfig.onDrag(component, target, delta);
  22319. };
  22320. const calcStartData = (dragConfig, comp) => ({
  22321. bounds: dragConfig.getBounds(),
  22322. height: getOuter$2(comp.element),
  22323. width: getOuter$1(comp.element)
  22324. });
  22325. const move = (component, dragConfig, dragState, dragMode, event) => {
  22326. const delta = dragState.update(dragMode, event);
  22327. const dragStartData = dragState.getStartData().getOrThunk(() => calcStartData(dragConfig, component));
  22328. delta.each(dlt => {
  22329. dragBy(component, dragConfig, dragStartData, dlt);
  22330. });
  22331. };
  22332. const stop = (component, blocker, dragConfig, dragState) => {
  22333. blocker.each(discard);
  22334. dragConfig.snaps.each(snapInfo => {
  22335. stopDrag(component, snapInfo);
  22336. });
  22337. const target = dragConfig.getTarget(component.element);
  22338. dragState.reset();
  22339. dragConfig.onDrop(component, target);
  22340. };
  22341. const handlers = events => (dragConfig, dragState) => {
  22342. const updateStartState = comp => {
  22343. dragState.setStartData(calcStartData(dragConfig, comp));
  22344. };
  22345. return derive$2([
  22346. run$1(windowScroll(), comp => {
  22347. dragState.getStartData().each(() => updateStartState(comp));
  22348. }),
  22349. ...events(dragConfig, dragState, updateStartState)
  22350. ]);
  22351. };
  22352. const init$2 = dragApi => derive$2([
  22353. run$1(mousedown(), dragApi.forceDrop),
  22354. run$1(mouseup(), dragApi.drop),
  22355. run$1(mousemove(), (comp, simulatedEvent) => {
  22356. dragApi.move(simulatedEvent.event);
  22357. }),
  22358. run$1(mouseout(), dragApi.delayDrop)
  22359. ]);
  22360. const getData$1 = event => Optional.from(SugarPosition(event.x, event.y));
  22361. const getDelta$1 = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
  22362. var MouseData = /*#__PURE__*/Object.freeze({
  22363. __proto__: null,
  22364. getData: getData$1,
  22365. getDelta: getDelta$1
  22366. });
  22367. const events$2 = (dragConfig, dragState, updateStartState) => [run$1(mousedown(), (component, simulatedEvent) => {
  22368. const raw = simulatedEvent.event.raw;
  22369. if (raw.button !== 0) {
  22370. return;
  22371. }
  22372. simulatedEvent.stop();
  22373. const stop$1 = () => stop(component, Optional.some(blocker), dragConfig, dragState);
  22374. const delayDrop = DelayedFunction(stop$1, 200);
  22375. const dragApi = {
  22376. drop: stop$1,
  22377. delayDrop: delayDrop.schedule,
  22378. forceDrop: stop$1,
  22379. move: event => {
  22380. delayDrop.cancel();
  22381. move(component, dragConfig, dragState, MouseData, event);
  22382. }
  22383. };
  22384. const blocker = createComponent(component, dragConfig.blockerClass, init$2(dragApi));
  22385. const start = () => {
  22386. updateStartState(component);
  22387. instigate(component, blocker);
  22388. };
  22389. start();
  22390. })];
  22391. const schema$5 = [
  22392. ...schema$6,
  22393. output$1('dragger', { handlers: handlers(events$2) })
  22394. ];
  22395. const init$1 = dragApi => derive$2([
  22396. run$1(touchstart(), dragApi.forceDrop),
  22397. run$1(touchend(), dragApi.drop),
  22398. run$1(touchcancel(), dragApi.drop),
  22399. run$1(touchmove(), (comp, simulatedEvent) => {
  22400. dragApi.move(simulatedEvent.event);
  22401. })
  22402. ]);
  22403. const getDataFrom = touches => {
  22404. const touch = touches[0];
  22405. return Optional.some(SugarPosition(touch.clientX, touch.clientY));
  22406. };
  22407. const getData = event => {
  22408. const raw = event.raw;
  22409. const touches = raw.touches;
  22410. return touches.length === 1 ? getDataFrom(touches) : Optional.none();
  22411. };
  22412. const getDelta = (old, nu) => SugarPosition(nu.left - old.left, nu.top - old.top);
  22413. var TouchData = /*#__PURE__*/Object.freeze({
  22414. __proto__: null,
  22415. getData: getData,
  22416. getDelta: getDelta
  22417. });
  22418. const events$1 = (dragConfig, dragState, updateStartState) => {
  22419. const blockerSingleton = value$2();
  22420. const stopBlocking = component => {
  22421. stop(component, blockerSingleton.get(), dragConfig, dragState);
  22422. blockerSingleton.clear();
  22423. };
  22424. return [
  22425. run$1(touchstart(), (component, simulatedEvent) => {
  22426. simulatedEvent.stop();
  22427. const stop = () => stopBlocking(component);
  22428. const dragApi = {
  22429. drop: stop,
  22430. delayDrop: noop,
  22431. forceDrop: stop,
  22432. move: event => {
  22433. move(component, dragConfig, dragState, TouchData, event);
  22434. }
  22435. };
  22436. const blocker = createComponent(component, dragConfig.blockerClass, init$1(dragApi));
  22437. blockerSingleton.set(blocker);
  22438. const start = () => {
  22439. updateStartState(component);
  22440. instigate(component, blocker);
  22441. };
  22442. start();
  22443. }),
  22444. run$1(touchmove(), (component, simulatedEvent) => {
  22445. simulatedEvent.stop();
  22446. move(component, dragConfig, dragState, TouchData, simulatedEvent.event);
  22447. }),
  22448. run$1(touchend(), (component, simulatedEvent) => {
  22449. simulatedEvent.stop();
  22450. stopBlocking(component);
  22451. }),
  22452. run$1(touchcancel(), stopBlocking)
  22453. ];
  22454. };
  22455. const schema$4 = [
  22456. ...schema$6,
  22457. output$1('dragger', { handlers: handlers(events$1) })
  22458. ];
  22459. const events = (dragConfig, dragState, updateStartState) => [
  22460. ...events$2(dragConfig, dragState, updateStartState),
  22461. ...events$1(dragConfig, dragState, updateStartState)
  22462. ];
  22463. const schema$3 = [
  22464. ...schema$6,
  22465. output$1('dragger', { handlers: handlers(events) })
  22466. ];
  22467. const mouse = schema$5;
  22468. const touch = schema$4;
  22469. const mouseOrTouch = schema$3;
  22470. var DraggingBranches = /*#__PURE__*/Object.freeze({
  22471. __proto__: null,
  22472. mouse: mouse,
  22473. touch: touch,
  22474. mouseOrTouch: mouseOrTouch
  22475. });
  22476. const init = () => {
  22477. let previous = Optional.none();
  22478. let startData = Optional.none();
  22479. const reset = () => {
  22480. previous = Optional.none();
  22481. startData = Optional.none();
  22482. };
  22483. const calculateDelta = (mode, nu) => {
  22484. const result = previous.map(old => mode.getDelta(old, nu));
  22485. previous = Optional.some(nu);
  22486. return result;
  22487. };
  22488. const update = (mode, dragEvent) => mode.getData(dragEvent).bind(nuData => calculateDelta(mode, nuData));
  22489. const setStartData = data => {
  22490. startData = Optional.some(data);
  22491. };
  22492. const getStartData = () => startData;
  22493. const readState = constant$1({});
  22494. return nu$8({
  22495. readState,
  22496. reset,
  22497. update,
  22498. getStartData,
  22499. setStartData
  22500. });
  22501. };
  22502. var DragState = /*#__PURE__*/Object.freeze({
  22503. __proto__: null,
  22504. init: init
  22505. });
  22506. const Dragging = createModes({
  22507. branchKey: 'mode',
  22508. branches: DraggingBranches,
  22509. name: 'dragging',
  22510. active: {
  22511. events: (dragConfig, dragState) => {
  22512. const dragger = dragConfig.dragger;
  22513. return dragger.handlers(dragConfig, dragState);
  22514. }
  22515. },
  22516. extra: {
  22517. snap: sConfig => ({
  22518. sensor: sConfig.sensor,
  22519. range: sConfig.range,
  22520. output: sConfig.output,
  22521. extra: Optional.from(sConfig.extra)
  22522. })
  22523. },
  22524. state: DragState,
  22525. apis: DraggingApis
  22526. });
  22527. const snapWidth = 40;
  22528. const snapOffset = snapWidth / 2;
  22529. const calcSnap = (selectorOpt, td, x, y, width, height) => selectorOpt.fold(() => Dragging.snap({
  22530. sensor: absolute(x - snapOffset, y - snapOffset),
  22531. range: SugarPosition(width, height),
  22532. output: absolute(Optional.some(x), Optional.some(y)),
  22533. extra: { td }
  22534. }), selectorHandle => {
  22535. const sensorLeft = x - snapOffset;
  22536. const sensorTop = y - snapOffset;
  22537. const sensorWidth = snapWidth;
  22538. const sensorHeight = snapWidth;
  22539. const rect = selectorHandle.element.dom.getBoundingClientRect();
  22540. return Dragging.snap({
  22541. sensor: absolute(sensorLeft, sensorTop),
  22542. range: SugarPosition(sensorWidth, sensorHeight),
  22543. output: absolute(Optional.some(x - rect.width / 2), Optional.some(y - rect.height / 2)),
  22544. extra: { td }
  22545. });
  22546. });
  22547. const getSnapsConfig = (getSnapPoints, cell, onChange) => {
  22548. const isSameCell = (cellOpt, td) => cellOpt.exists(currentTd => eq(currentTd, td));
  22549. return {
  22550. getSnapPoints,
  22551. leftAttr: 'data-drag-left',
  22552. topAttr: 'data-drag-top',
  22553. onSensor: (component, extra) => {
  22554. const td = extra.td;
  22555. if (!isSameCell(cell.get(), td)) {
  22556. cell.set(td);
  22557. onChange(td);
  22558. }
  22559. },
  22560. mustSnap: true
  22561. };
  22562. };
  22563. const createSelector = snaps => record(Button.sketch({
  22564. dom: {
  22565. tag: 'div',
  22566. classes: ['tox-selector']
  22567. },
  22568. buttonBehaviours: derive$1([
  22569. Dragging.config({
  22570. mode: 'mouseOrTouch',
  22571. blockerClass: 'blocker',
  22572. snaps
  22573. }),
  22574. Unselecting.config({})
  22575. ]),
  22576. eventOrder: {
  22577. mousedown: [
  22578. 'dragging',
  22579. 'alloy.base.behaviour'
  22580. ],
  22581. touchstart: [
  22582. 'dragging',
  22583. 'alloy.base.behaviour'
  22584. ]
  22585. }
  22586. }));
  22587. const setup$4 = (editor, sink) => {
  22588. const tlTds = Cell([]);
  22589. const brTds = Cell([]);
  22590. const isVisible = Cell(false);
  22591. const startCell = value$2();
  22592. const finishCell = value$2();
  22593. const getTopLeftSnap = td => {
  22594. const box = absolute$2(td);
  22595. return calcSnap(memTopLeft.getOpt(sink), td, box.x, box.y, box.width, box.height);
  22596. };
  22597. const getTopLeftSnaps = () => map$2(tlTds.get(), td => getTopLeftSnap(td));
  22598. const getBottomRightSnap = td => {
  22599. const box = absolute$2(td);
  22600. return calcSnap(memBottomRight.getOpt(sink), td, box.right, box.bottom, box.width, box.height);
  22601. };
  22602. const getBottomRightSnaps = () => map$2(brTds.get(), td => getBottomRightSnap(td));
  22603. const topLeftSnaps = getSnapsConfig(getTopLeftSnaps, startCell, start => {
  22604. finishCell.get().each(finish => {
  22605. editor.dispatch('TableSelectorChange', {
  22606. start,
  22607. finish
  22608. });
  22609. });
  22610. });
  22611. const bottomRightSnaps = getSnapsConfig(getBottomRightSnaps, finishCell, finish => {
  22612. startCell.get().each(start => {
  22613. editor.dispatch('TableSelectorChange', {
  22614. start,
  22615. finish
  22616. });
  22617. });
  22618. });
  22619. const memTopLeft = createSelector(topLeftSnaps);
  22620. const memBottomRight = createSelector(bottomRightSnaps);
  22621. const topLeft = build$1(memTopLeft.asSpec());
  22622. const bottomRight = build$1(memBottomRight.asSpec());
  22623. const showOrHideHandle = (selector, cell, isAbove, isBelow) => {
  22624. const cellRect = cell.dom.getBoundingClientRect();
  22625. remove$6(selector.element, 'display');
  22626. const viewportHeight = defaultView(SugarElement.fromDom(editor.getBody())).dom.innerHeight;
  22627. const aboveViewport = isAbove(cellRect);
  22628. const belowViewport = isBelow(cellRect, viewportHeight);
  22629. if (aboveViewport || belowViewport) {
  22630. set$8(selector.element, 'display', 'none');
  22631. }
  22632. };
  22633. const snapTo = (selector, cell, getSnapConfig, pos) => {
  22634. const snap = getSnapConfig(cell);
  22635. Dragging.snapTo(selector, snap);
  22636. const isAbove = rect => rect[pos] < 0;
  22637. const isBelow = (rect, viewportHeight) => rect[pos] > viewportHeight;
  22638. showOrHideHandle(selector, cell, isAbove, isBelow);
  22639. };
  22640. const snapTopLeft = cell => snapTo(topLeft, cell, getTopLeftSnap, 'top');
  22641. const snapLastTopLeft = () => startCell.get().each(snapTopLeft);
  22642. const snapBottomRight = cell => snapTo(bottomRight, cell, getBottomRightSnap, 'bottom');
  22643. const snapLastBottomRight = () => finishCell.get().each(snapBottomRight);
  22644. if (detect$1().deviceType.isTouch()) {
  22645. editor.on('TableSelectionChange', e => {
  22646. if (!isVisible.get()) {
  22647. attach(sink, topLeft);
  22648. attach(sink, bottomRight);
  22649. isVisible.set(true);
  22650. }
  22651. startCell.set(e.start);
  22652. finishCell.set(e.finish);
  22653. e.otherCells.each(otherCells => {
  22654. tlTds.set(otherCells.upOrLeftCells);
  22655. brTds.set(otherCells.downOrRightCells);
  22656. snapTopLeft(e.start);
  22657. snapBottomRight(e.finish);
  22658. });
  22659. });
  22660. editor.on('ResizeEditor ResizeWindow ScrollContent', () => {
  22661. snapLastTopLeft();
  22662. snapLastBottomRight();
  22663. });
  22664. editor.on('TableSelectionClear', () => {
  22665. if (isVisible.get()) {
  22666. detach(topLeft);
  22667. detach(bottomRight);
  22668. isVisible.set(false);
  22669. }
  22670. startCell.clear();
  22671. finishCell.clear();
  22672. });
  22673. }
  22674. };
  22675. 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";
  22676. const isHidden = elm => elm.nodeName === 'BR' || !!elm.getAttribute('data-mce-bogus') || elm.getAttribute('data-mce-type') === 'bookmark';
  22677. const renderElementPath = (editor, settings, providersBackstage) => {
  22678. var _a;
  22679. const delimiter = (_a = settings.delimiter) !== null && _a !== void 0 ? _a : '\u203A';
  22680. const renderElement = (name, element, index) => Button.sketch({
  22681. dom: {
  22682. tag: 'div',
  22683. classes: ['tox-statusbar__path-item'],
  22684. attributes: {
  22685. 'data-index': index,
  22686. 'aria-level': index + 1
  22687. }
  22688. },
  22689. components: [text$1(name)],
  22690. action: _btn => {
  22691. editor.focus();
  22692. editor.selection.select(element);
  22693. editor.nodeChanged();
  22694. },
  22695. buttonBehaviours: derive$1([
  22696. DisablingConfigs.button(providersBackstage.isDisabled),
  22697. receivingConfig()
  22698. ])
  22699. });
  22700. const renderDivider = () => ({
  22701. dom: {
  22702. tag: 'div',
  22703. classes: ['tox-statusbar__path-divider'],
  22704. attributes: { 'aria-hidden': true }
  22705. },
  22706. components: [text$1(` ${ delimiter } `)]
  22707. });
  22708. const renderPathData = data => foldl(data, (acc, path, index) => {
  22709. const element = renderElement(path.name, path.element, index);
  22710. if (index === 0) {
  22711. return acc.concat([element]);
  22712. } else {
  22713. return acc.concat([
  22714. renderDivider(),
  22715. element
  22716. ]);
  22717. }
  22718. }, []);
  22719. const updatePath = parents => {
  22720. const newPath = [];
  22721. let i = parents.length;
  22722. while (i-- > 0) {
  22723. const parent = parents[i];
  22724. if (parent.nodeType === 1 && !isHidden(parent)) {
  22725. const args = editor.dispatch('ResolveName', {
  22726. name: parent.nodeName.toLowerCase(),
  22727. target: parent
  22728. });
  22729. if (!args.isDefaultPrevented()) {
  22730. newPath.push({
  22731. name: args.name,
  22732. element: parent
  22733. });
  22734. }
  22735. if (args.isPropagationStopped()) {
  22736. break;
  22737. }
  22738. }
  22739. }
  22740. return newPath;
  22741. };
  22742. return {
  22743. dom: {
  22744. tag: 'div',
  22745. classes: ['tox-statusbar__path'],
  22746. attributes: { role: 'navigation' }
  22747. },
  22748. behaviours: derive$1([
  22749. Keying.config({
  22750. mode: 'flow',
  22751. selector: 'div[role=button]'
  22752. }),
  22753. Disabling.config({ disabled: providersBackstage.isDisabled }),
  22754. receivingConfig(),
  22755. Tabstopping.config({}),
  22756. Replacing.config({}),
  22757. config('elementPathEvents', [runOnAttached((comp, _e) => {
  22758. editor.shortcuts.add('alt+F11', 'focus statusbar elementpath', () => Keying.focusIn(comp));
  22759. editor.on('NodeChange', e => {
  22760. const newPath = updatePath(e.parents);
  22761. const newChildren = newPath.length > 0 ? renderPathData(newPath) : [];
  22762. Replacing.set(comp, newChildren);
  22763. });
  22764. })])
  22765. ]),
  22766. components: []
  22767. };
  22768. };
  22769. var ResizeTypes;
  22770. (function (ResizeTypes) {
  22771. ResizeTypes[ResizeTypes['None'] = 0] = 'None';
  22772. ResizeTypes[ResizeTypes['Both'] = 1] = 'Both';
  22773. ResizeTypes[ResizeTypes['Vertical'] = 2] = 'Vertical';
  22774. }(ResizeTypes || (ResizeTypes = {})));
  22775. const getDimensions = (editor, deltas, resizeType, originalHeight, originalWidth) => {
  22776. const dimensions = {};
  22777. dimensions.height = calcCappedSize(originalHeight + deltas.top, getMinHeightOption(editor), getMaxHeightOption(editor));
  22778. if (resizeType === ResizeTypes.Both) {
  22779. dimensions.width = calcCappedSize(originalWidth + deltas.left, getMinWidthOption(editor), getMaxWidthOption(editor));
  22780. }
  22781. return dimensions;
  22782. };
  22783. const resize = (editor, deltas, resizeType) => {
  22784. const container = SugarElement.fromDom(editor.getContainer());
  22785. const dimensions = getDimensions(editor, deltas, resizeType, get$d(container), get$c(container));
  22786. each(dimensions, (val, dim) => set$8(container, dim, numToPx(val)));
  22787. fireResizeEditor(editor);
  22788. };
  22789. const getResizeType = editor => {
  22790. const resize = getResize(editor);
  22791. if (resize === false) {
  22792. return ResizeTypes.None;
  22793. } else if (resize === 'both') {
  22794. return ResizeTypes.Both;
  22795. } else {
  22796. return ResizeTypes.Vertical;
  22797. }
  22798. };
  22799. const keyboardHandler = (editor, resizeType, x, y) => {
  22800. const scale = 20;
  22801. const delta = SugarPosition(x * scale, y * scale);
  22802. resize(editor, delta, resizeType);
  22803. return Optional.some(true);
  22804. };
  22805. const renderResizeHandler = (editor, providersBackstage) => {
  22806. const resizeType = getResizeType(editor);
  22807. if (resizeType === ResizeTypes.None) {
  22808. return Optional.none();
  22809. }
  22810. return Optional.some(render$3('resize-handle', {
  22811. tag: 'div',
  22812. classes: ['tox-statusbar__resize-handle'],
  22813. attributes: { title: providersBackstage.translate('Resize') },
  22814. behaviours: [
  22815. Dragging.config({
  22816. mode: 'mouse',
  22817. repositionTarget: false,
  22818. onDrag: (_comp, _target, delta) => resize(editor, delta, resizeType),
  22819. blockerClass: 'tox-blocker'
  22820. }),
  22821. Keying.config({
  22822. mode: 'special',
  22823. onLeft: () => keyboardHandler(editor, resizeType, -1, 0),
  22824. onRight: () => keyboardHandler(editor, resizeType, 1, 0),
  22825. onUp: () => keyboardHandler(editor, resizeType, 0, -1),
  22826. onDown: () => keyboardHandler(editor, resizeType, 0, 1)
  22827. }),
  22828. Tabstopping.config({}),
  22829. Focusing.config({})
  22830. ]
  22831. }, providersBackstage.icons));
  22832. };
  22833. const renderWordCount = (editor, providersBackstage) => {
  22834. const replaceCountText = (comp, count, mode) => Replacing.set(comp, [text$1(providersBackstage.translate([
  22835. '{0} ' + mode,
  22836. count[mode]
  22837. ]))]);
  22838. return Button.sketch({
  22839. dom: {
  22840. tag: 'button',
  22841. classes: ['tox-statusbar__wordcount']
  22842. },
  22843. components: [],
  22844. buttonBehaviours: derive$1([
  22845. DisablingConfigs.button(providersBackstage.isDisabled),
  22846. receivingConfig(),
  22847. Tabstopping.config({}),
  22848. Replacing.config({}),
  22849. Representing.config({
  22850. store: {
  22851. mode: 'memory',
  22852. initialValue: {
  22853. mode: 'words',
  22854. count: {
  22855. words: 0,
  22856. characters: 0
  22857. }
  22858. }
  22859. }
  22860. }),
  22861. config('wordcount-events', [
  22862. runOnExecute$1(comp => {
  22863. const currentVal = Representing.getValue(comp);
  22864. const newMode = currentVal.mode === 'words' ? 'characters' : 'words';
  22865. Representing.setValue(comp, {
  22866. mode: newMode,
  22867. count: currentVal.count
  22868. });
  22869. replaceCountText(comp, currentVal.count, newMode);
  22870. }),
  22871. runOnAttached(comp => {
  22872. editor.on('wordCountUpdate', e => {
  22873. const {mode} = Representing.getValue(comp);
  22874. Representing.setValue(comp, {
  22875. mode,
  22876. count: e.wordCount
  22877. });
  22878. replaceCountText(comp, e.wordCount, mode);
  22879. });
  22880. })
  22881. ])
  22882. ]),
  22883. eventOrder: {
  22884. [execute$5()]: [
  22885. 'disabling',
  22886. 'alloy.base.behaviour',
  22887. 'wordcount-events'
  22888. ]
  22889. }
  22890. });
  22891. };
  22892. const renderStatusbar = (editor, providersBackstage) => {
  22893. const renderBranding = () => {
  22894. return {
  22895. dom: {
  22896. tag: 'span',
  22897. classes: ['tox-statusbar__branding']
  22898. },
  22899. components: [{
  22900. dom: {
  22901. tag: 'a',
  22902. attributes: {
  22903. 'href': 'https://www.tiny.cloud/powered-by-tiny?utm_campaign=editor_referral&utm_medium=poweredby&utm_source=tinymce&utm_content=v6',
  22904. 'rel': 'noopener',
  22905. 'target': '_blank',
  22906. 'aria-label': global$8.translate([
  22907. 'Powered by {0}',
  22908. 'Tiny'
  22909. ])
  22910. },
  22911. innerHtml: Logo.trim()
  22912. },
  22913. behaviours: derive$1([Focusing.config({})])
  22914. }]
  22915. };
  22916. };
  22917. const getTextComponents = () => {
  22918. const components = [];
  22919. if (useElementPath(editor)) {
  22920. components.push(renderElementPath(editor, {}, providersBackstage));
  22921. }
  22922. if (editor.hasPlugin('wordcount')) {
  22923. components.push(renderWordCount(editor, providersBackstage));
  22924. }
  22925. if (useBranding(editor)) {
  22926. components.push(renderBranding());
  22927. }
  22928. if (components.length > 0) {
  22929. return [{
  22930. dom: {
  22931. tag: 'div',
  22932. classes: ['tox-statusbar__text-container']
  22933. },
  22934. components
  22935. }];
  22936. }
  22937. return [];
  22938. };
  22939. const getComponents = () => {
  22940. const components = getTextComponents();
  22941. const resizeHandler = renderResizeHandler(editor, providersBackstage);
  22942. return components.concat(resizeHandler.toArray());
  22943. };
  22944. return {
  22945. dom: {
  22946. tag: 'div',
  22947. classes: ['tox-statusbar']
  22948. },
  22949. components: getComponents()
  22950. };
  22951. };
  22952. const getLazyMothership = singleton => singleton.get().getOrDie('UI has not been rendered');
  22953. const setup$3 = editor => {
  22954. const isInline = editor.inline;
  22955. const mode = isInline ? Inline : Iframe;
  22956. const header = isStickyToolbar(editor) ? StickyHeader : StaticHeader;
  22957. const lazySink = value$2();
  22958. const lazyOuterContainer = value$2();
  22959. const lazyMothership = value$2();
  22960. const lazyUiMothership = value$2();
  22961. const platform = detect$1();
  22962. const isTouch = platform.deviceType.isTouch();
  22963. const touchPlatformClass = 'tox-platform-touch';
  22964. const deviceClasses = isTouch ? [touchPlatformClass] : [];
  22965. const isToolbarBottom = isToolbarLocationBottom(editor);
  22966. const toolbarMode = getToolbarMode(editor);
  22967. const memAnchorBar = record({
  22968. dom: {
  22969. tag: 'div',
  22970. classes: ['tox-anchorbar']
  22971. }
  22972. });
  22973. const lazyHeader = () => lazyOuterContainer.get().bind(OuterContainer.getHeader);
  22974. const lazySinkResult = () => Result.fromOption(lazySink.get(), 'UI has not been rendered');
  22975. const lazyAnchorBar = () => lazyOuterContainer.get().bind(container => memAnchorBar.getOpt(container)).getOrDie('Could not find a anchor bar element');
  22976. const lazyToolbar = () => lazyOuterContainer.get().bind(container => OuterContainer.getToolbar(container)).getOrDie('Could not find more toolbar element');
  22977. const lazyThrobber = () => lazyOuterContainer.get().bind(container => OuterContainer.getThrobber(container)).getOrDie('Could not find throbber element');
  22978. const backstage = init$7(lazySinkResult, editor, lazyAnchorBar);
  22979. const makeHeaderPart = () => {
  22980. const verticalDirAttributes = { attributes: { [Attribute]: isToolbarBottom ? AttributeValue.BottomToTop : AttributeValue.TopToBottom } };
  22981. const partMenubar = OuterContainer.parts.menubar({
  22982. dom: {
  22983. tag: 'div',
  22984. classes: ['tox-menubar']
  22985. },
  22986. backstage,
  22987. onEscape: () => {
  22988. editor.focus();
  22989. }
  22990. });
  22991. const partToolbar = OuterContainer.parts.toolbar({
  22992. dom: {
  22993. tag: 'div',
  22994. classes: ['tox-toolbar']
  22995. },
  22996. getSink: lazySinkResult,
  22997. providers: backstage.shared.providers,
  22998. onEscape: () => {
  22999. editor.focus();
  23000. },
  23001. type: toolbarMode,
  23002. lazyToolbar,
  23003. lazyHeader: () => lazyHeader().getOrDie('Could not find header element'),
  23004. ...verticalDirAttributes
  23005. });
  23006. const partMultipleToolbar = OuterContainer.parts['multiple-toolbar']({
  23007. dom: {
  23008. tag: 'div',
  23009. classes: ['tox-toolbar-overlord']
  23010. },
  23011. providers: backstage.shared.providers,
  23012. onEscape: () => {
  23013. editor.focus();
  23014. },
  23015. type: toolbarMode
  23016. });
  23017. const hasMultipleToolbar = isMultipleToolbars(editor);
  23018. const hasToolbar = isToolbarEnabled(editor);
  23019. const hasMenubar = isMenubarEnabled(editor);
  23020. const getPartToolbar = () => {
  23021. if (hasMultipleToolbar) {
  23022. return [partMultipleToolbar];
  23023. } else if (hasToolbar) {
  23024. return [partToolbar];
  23025. } else {
  23026. return [];
  23027. }
  23028. };
  23029. return OuterContainer.parts.header({
  23030. dom: {
  23031. tag: 'div',
  23032. classes: ['tox-editor-header'],
  23033. ...verticalDirAttributes
  23034. },
  23035. components: flatten([
  23036. hasMenubar ? [partMenubar] : [],
  23037. getPartToolbar(),
  23038. useFixedContainer(editor) ? [] : [memAnchorBar.asSpec()]
  23039. ]),
  23040. sticky: isStickyToolbar(editor),
  23041. editor,
  23042. sharedBackstage: backstage.shared
  23043. });
  23044. };
  23045. const makeSidebarDefinition = () => {
  23046. const partSocket = OuterContainer.parts.socket({
  23047. dom: {
  23048. tag: 'div',
  23049. classes: ['tox-edit-area']
  23050. }
  23051. });
  23052. const partSidebar = OuterContainer.parts.sidebar({
  23053. dom: {
  23054. tag: 'div',
  23055. classes: ['tox-sidebar']
  23056. }
  23057. });
  23058. return {
  23059. dom: {
  23060. tag: 'div',
  23061. classes: ['tox-sidebar-wrap']
  23062. },
  23063. components: [
  23064. partSocket,
  23065. partSidebar
  23066. ]
  23067. };
  23068. };
  23069. const renderSink = () => {
  23070. const uiContainer = getUiContainer(editor);
  23071. const isGridUiContainer = eq(body(), uiContainer) && get$e(uiContainer, 'display') === 'grid';
  23072. const sinkSpec = {
  23073. dom: {
  23074. tag: 'div',
  23075. classes: [
  23076. 'tox',
  23077. 'tox-silver-sink',
  23078. 'tox-tinymce-aux'
  23079. ].concat(deviceClasses),
  23080. attributes: { ...global$8.isRtl() ? { dir: 'rtl' } : {} }
  23081. },
  23082. behaviours: derive$1([Positioning.config({ useFixed: () => header.isDocked(lazyHeader) })])
  23083. };
  23084. const reactiveWidthSpec = {
  23085. dom: { styles: { width: document.body.clientWidth + 'px' } },
  23086. events: derive$2([run$1(windowResize(), comp => {
  23087. set$8(comp.element, 'width', document.body.clientWidth + 'px');
  23088. })])
  23089. };
  23090. const sink = build$1(deepMerge(sinkSpec, isGridUiContainer ? reactiveWidthSpec : {}));
  23091. const uiMothership = takeover(sink);
  23092. lazySink.set(sink);
  23093. lazyUiMothership.set(uiMothership);
  23094. return {
  23095. sink,
  23096. uiMothership
  23097. };
  23098. };
  23099. const renderContainer = () => {
  23100. const partHeader = makeHeaderPart();
  23101. const sidebarContainer = makeSidebarDefinition();
  23102. const partThrobber = OuterContainer.parts.throbber({
  23103. dom: {
  23104. tag: 'div',
  23105. classes: ['tox-throbber']
  23106. },
  23107. backstage
  23108. });
  23109. const statusbar = useStatusBar(editor) && !isInline ? Optional.some(renderStatusbar(editor, backstage.shared.providers)) : Optional.none();
  23110. const editorComponents = flatten([
  23111. isToolbarBottom ? [] : [partHeader],
  23112. isInline ? [] : [sidebarContainer],
  23113. isToolbarBottom ? [partHeader] : []
  23114. ]);
  23115. const editorContainer = {
  23116. dom: {
  23117. tag: 'div',
  23118. classes: ['tox-editor-container']
  23119. },
  23120. components: editorComponents
  23121. };
  23122. const containerComponents = flatten([
  23123. [editorContainer],
  23124. isInline ? [] : statusbar.toArray(),
  23125. [partThrobber]
  23126. ]);
  23127. const isHidden = isDistractionFree(editor);
  23128. const attributes = {
  23129. role: 'application',
  23130. ...global$8.isRtl() ? { dir: 'rtl' } : {},
  23131. ...isHidden ? { 'aria-hidden': 'true' } : {}
  23132. };
  23133. const outerContainer = build$1(OuterContainer.sketch({
  23134. dom: {
  23135. tag: 'div',
  23136. classes: [
  23137. 'tox',
  23138. 'tox-tinymce'
  23139. ].concat(isInline ? ['tox-tinymce-inline'] : []).concat(isToolbarBottom ? ['tox-tinymce--toolbar-bottom'] : []).concat(deviceClasses),
  23140. styles: {
  23141. visibility: 'hidden',
  23142. ...isHidden ? {
  23143. opacity: '0',
  23144. border: '0'
  23145. } : {}
  23146. },
  23147. attributes
  23148. },
  23149. components: containerComponents,
  23150. behaviours: derive$1([
  23151. receivingConfig(),
  23152. Disabling.config({ disableClass: 'tox-tinymce--disabled' }),
  23153. Keying.config({
  23154. mode: 'cyclic',
  23155. 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'
  23156. })
  23157. ])
  23158. }));
  23159. const mothership = takeover(outerContainer);
  23160. lazyOuterContainer.set(outerContainer);
  23161. lazyMothership.set(mothership);
  23162. return {
  23163. mothership,
  23164. outerContainer
  23165. };
  23166. };
  23167. const setEditorSize = outerContainer => {
  23168. const parsedHeight = numToPx(getHeightWithFallback(editor));
  23169. const parsedWidth = numToPx(getWidthWithFallback(editor));
  23170. if (!editor.inline) {
  23171. if (isValidValue('div', 'width', parsedWidth)) {
  23172. set$8(outerContainer.element, 'width', parsedWidth);
  23173. }
  23174. if (isValidValue('div', 'height', parsedHeight)) {
  23175. set$8(outerContainer.element, 'height', parsedHeight);
  23176. } else {
  23177. set$8(outerContainer.element, 'height', '400px');
  23178. }
  23179. }
  23180. return parsedHeight;
  23181. };
  23182. const setupShortcutsAndCommands = outerContainer => {
  23183. editor.addShortcut('alt+F9', 'focus menubar', () => {
  23184. OuterContainer.focusMenubar(outerContainer);
  23185. });
  23186. editor.addShortcut('alt+F10', 'focus toolbar', () => {
  23187. OuterContainer.focusToolbar(outerContainer);
  23188. });
  23189. editor.addCommand('ToggleToolbarDrawer', () => {
  23190. OuterContainer.toggleToolbarDrawer(outerContainer);
  23191. });
  23192. editor.addQueryStateHandler('ToggleToolbarDrawer', () => OuterContainer.isToolbarDrawerToggled(outerContainer));
  23193. };
  23194. const renderUI = () => {
  23195. const {mothership, outerContainer} = renderContainer();
  23196. const {uiMothership, sink} = renderSink();
  23197. map$1(getToolbarGroups(editor), (toolbarGroupButtonConfig, name) => {
  23198. editor.ui.registry.addGroupToolbarButton(name, toolbarGroupButtonConfig);
  23199. });
  23200. const {buttons, menuItems, contextToolbars, sidebars} = editor.ui.registry.getAll();
  23201. const toolbarOpt = getMultipleToolbarsOption(editor);
  23202. const rawUiConfig = {
  23203. menuItems,
  23204. menus: getMenus(editor),
  23205. menubar: getMenubar(editor),
  23206. toolbar: toolbarOpt.getOrThunk(() => getToolbar(editor)),
  23207. allowToolbarGroups: toolbarMode === ToolbarMode$1.floating,
  23208. buttons,
  23209. sidebar: sidebars
  23210. };
  23211. setupShortcutsAndCommands(outerContainer);
  23212. setup$b(editor, mothership, uiMothership);
  23213. header.setup(editor, backstage.shared, lazyHeader);
  23214. setup$6(editor, backstage);
  23215. setup$5(editor, lazySinkResult, backstage);
  23216. setup$8(editor);
  23217. setup$7(editor, lazyThrobber, backstage.shared);
  23218. register$9(editor, contextToolbars, sink, { backstage });
  23219. setup$4(editor, sink);
  23220. const elm = editor.getElement();
  23221. const height = setEditorSize(outerContainer);
  23222. const uiComponents = {
  23223. mothership,
  23224. uiMothership,
  23225. outerContainer,
  23226. sink
  23227. };
  23228. const args = {
  23229. targetNode: elm,
  23230. height
  23231. };
  23232. return mode.render(editor, uiComponents, rawUiConfig, backstage, args);
  23233. };
  23234. const getMothership = () => getLazyMothership(lazyMothership);
  23235. const getUiMothership = () => getLazyMothership(lazyUiMothership);
  23236. return {
  23237. getMothership,
  23238. getUiMothership,
  23239. backstage,
  23240. renderUI
  23241. };
  23242. };
  23243. const describedBy = (describedElement, describeElement) => {
  23244. const describeId = Optional.from(get$f(describedElement, 'id')).fold(() => {
  23245. const id = generate$6('dialog-describe');
  23246. set$9(describeElement, 'id', id);
  23247. return id;
  23248. }, identity);
  23249. set$9(describedElement, 'aria-describedby', describeId);
  23250. };
  23251. const labelledBy = (labelledElement, labelElement) => {
  23252. const labelId = getOpt(labelledElement, 'id').fold(() => {
  23253. const id = generate$6('dialog-label');
  23254. set$9(labelElement, 'id', id);
  23255. return id;
  23256. }, identity);
  23257. set$9(labelledElement, 'aria-labelledby', labelId);
  23258. };
  23259. const schema$2 = constant$1([
  23260. required$1('lazySink'),
  23261. option$3('dragBlockClass'),
  23262. defaultedFunction('getBounds', win),
  23263. defaulted('useTabstopAt', always),
  23264. defaulted('eventOrder', {}),
  23265. field('modalBehaviours', [Keying]),
  23266. onKeyboardHandler('onExecute'),
  23267. onStrictKeyboardHandler('onEscape')
  23268. ]);
  23269. const basic = { sketch: identity };
  23270. const parts$2 = constant$1([
  23271. optional({
  23272. name: 'draghandle',
  23273. overrides: (detail, spec) => {
  23274. return {
  23275. behaviours: derive$1([Dragging.config({
  23276. mode: 'mouse',
  23277. getTarget: handle => {
  23278. return ancestor(handle, '[role="dialog"]').getOr(handle);
  23279. },
  23280. 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),
  23281. getBounds: detail.getDragBounds
  23282. })])
  23283. };
  23284. }
  23285. }),
  23286. required({
  23287. schema: [required$1('dom')],
  23288. name: 'title'
  23289. }),
  23290. required({
  23291. factory: basic,
  23292. schema: [required$1('dom')],
  23293. name: 'close'
  23294. }),
  23295. required({
  23296. factory: basic,
  23297. schema: [required$1('dom')],
  23298. name: 'body'
  23299. }),
  23300. optional({
  23301. factory: basic,
  23302. schema: [required$1('dom')],
  23303. name: 'footer'
  23304. }),
  23305. external({
  23306. factory: {
  23307. sketch: (spec, detail) => ({
  23308. ...spec,
  23309. dom: detail.dom,
  23310. components: detail.components
  23311. })
  23312. },
  23313. schema: [
  23314. defaulted('dom', {
  23315. tag: 'div',
  23316. styles: {
  23317. position: 'fixed',
  23318. left: '0px',
  23319. top: '0px',
  23320. right: '0px',
  23321. bottom: '0px'
  23322. }
  23323. }),
  23324. defaulted('components', [])
  23325. ],
  23326. name: 'blocker'
  23327. })
  23328. ]);
  23329. const factory$4 = (detail, components, spec, externals) => {
  23330. const dialogComp = value$2();
  23331. const showDialog = dialog => {
  23332. dialogComp.set(dialog);
  23333. const sink = detail.lazySink(dialog).getOrDie();
  23334. const externalBlocker = externals.blocker();
  23335. const blocker = sink.getSystem().build({
  23336. ...externalBlocker,
  23337. components: externalBlocker.components.concat([premade(dialog)]),
  23338. behaviours: derive$1([
  23339. Focusing.config({}),
  23340. config('dialog-blocker-events', [runOnSource(focusin(), () => {
  23341. Keying.focusIn(dialog);
  23342. })])
  23343. ])
  23344. });
  23345. attach(sink, blocker);
  23346. Keying.focusIn(dialog);
  23347. };
  23348. const hideDialog = dialog => {
  23349. dialogComp.clear();
  23350. parent(dialog.element).each(blockerDom => {
  23351. dialog.getSystem().getByDom(blockerDom).each(blocker => {
  23352. detach(blocker);
  23353. });
  23354. });
  23355. };
  23356. const getDialogBody = dialog => getPartOrDie(dialog, detail, 'body');
  23357. const getDialogFooter = dialog => getPartOrDie(dialog, detail, 'footer');
  23358. const setBusy = (dialog, getBusySpec) => {
  23359. Blocking.block(dialog, getBusySpec);
  23360. };
  23361. const setIdle = dialog => {
  23362. Blocking.unblock(dialog);
  23363. };
  23364. const modalEventsId = generate$6('modal-events');
  23365. const eventOrder = {
  23366. ...detail.eventOrder,
  23367. [attachedToDom()]: [modalEventsId].concat(detail.eventOrder['alloy.system.attached'] || [])
  23368. };
  23369. return {
  23370. uid: detail.uid,
  23371. dom: detail.dom,
  23372. components,
  23373. apis: {
  23374. show: showDialog,
  23375. hide: hideDialog,
  23376. getBody: getDialogBody,
  23377. getFooter: getDialogFooter,
  23378. setIdle,
  23379. setBusy
  23380. },
  23381. eventOrder,
  23382. domModification: {
  23383. attributes: {
  23384. 'role': 'dialog',
  23385. 'aria-modal': 'true'
  23386. }
  23387. },
  23388. behaviours: augment(detail.modalBehaviours, [
  23389. Replacing.config({}),
  23390. Keying.config({
  23391. mode: 'cyclic',
  23392. onEnter: detail.onExecute,
  23393. onEscape: detail.onEscape,
  23394. useTabstopAt: detail.useTabstopAt
  23395. }),
  23396. Blocking.config({ getRoot: dialogComp.get }),
  23397. config(modalEventsId, [runOnAttached(c => {
  23398. labelledBy(c.element, getPartOrDie(c, detail, 'title').element);
  23399. describedBy(c.element, getPartOrDie(c, detail, 'body').element);
  23400. })])
  23401. ])
  23402. };
  23403. };
  23404. const ModalDialog = composite({
  23405. name: 'ModalDialog',
  23406. configFields: schema$2(),
  23407. partFields: parts$2(),
  23408. factory: factory$4,
  23409. apis: {
  23410. show: (apis, dialog) => {
  23411. apis.show(dialog);
  23412. },
  23413. hide: (apis, dialog) => {
  23414. apis.hide(dialog);
  23415. },
  23416. getBody: (apis, dialog) => apis.getBody(dialog),
  23417. getFooter: (apis, dialog) => apis.getFooter(dialog),
  23418. setBusy: (apis, dialog, getBusySpec) => {
  23419. apis.setBusy(dialog, getBusySpec);
  23420. },
  23421. setIdle: (apis, dialog) => {
  23422. apis.setIdle(dialog);
  23423. }
  23424. }
  23425. });
  23426. const dialogToggleMenuItemSchema = objOf([
  23427. type,
  23428. name$1
  23429. ].concat(commonMenuItemFields));
  23430. const dialogToggleMenuItemDataProcessor = boolean;
  23431. const baseFooterButtonFields = [
  23432. generatedName('button'),
  23433. optionalIcon,
  23434. defaultedStringEnum('align', 'end', [
  23435. 'start',
  23436. 'end'
  23437. ]),
  23438. primary,
  23439. enabled,
  23440. optionStringEnum('buttonType', [
  23441. 'primary',
  23442. 'secondary'
  23443. ])
  23444. ];
  23445. const dialogFooterButtonFields = [
  23446. ...baseFooterButtonFields,
  23447. text
  23448. ];
  23449. const normalFooterButtonFields = [
  23450. requiredStringEnum('type', [
  23451. 'submit',
  23452. 'cancel',
  23453. 'custom'
  23454. ]),
  23455. ...dialogFooterButtonFields
  23456. ];
  23457. const menuFooterButtonFields = [
  23458. requiredStringEnum('type', ['menu']),
  23459. optionalText,
  23460. optionalTooltip,
  23461. optionalIcon,
  23462. requiredArrayOf('items', dialogToggleMenuItemSchema),
  23463. ...baseFooterButtonFields
  23464. ];
  23465. const dialogFooterButtonSchema = choose$1('type', {
  23466. submit: normalFooterButtonFields,
  23467. cancel: normalFooterButtonFields,
  23468. custom: normalFooterButtonFields,
  23469. menu: menuFooterButtonFields
  23470. });
  23471. const alertBannerFields = [
  23472. type,
  23473. text,
  23474. requiredStringEnum('level', [
  23475. 'info',
  23476. 'warn',
  23477. 'error',
  23478. 'success'
  23479. ]),
  23480. icon,
  23481. defaulted('url', '')
  23482. ];
  23483. const alertBannerSchema = objOf(alertBannerFields);
  23484. const createBarFields = itemsField => [
  23485. type,
  23486. itemsField
  23487. ];
  23488. const buttonFields = [
  23489. type,
  23490. text,
  23491. enabled,
  23492. generatedName('button'),
  23493. optionalIcon,
  23494. borderless,
  23495. optionStringEnum('buttonType', [
  23496. 'primary',
  23497. 'secondary',
  23498. 'toolbar'
  23499. ]),
  23500. primary
  23501. ];
  23502. const buttonSchema = objOf(buttonFields);
  23503. const formComponentFields = [
  23504. type,
  23505. name$1
  23506. ];
  23507. const formComponentWithLabelFields = formComponentFields.concat([optionalLabel]);
  23508. const checkboxFields = formComponentFields.concat([
  23509. label,
  23510. enabled
  23511. ]);
  23512. const checkboxSchema = objOf(checkboxFields);
  23513. const checkboxDataProcessor = boolean;
  23514. const collectionFields = formComponentWithLabelFields.concat([defaultedColumns('auto')]);
  23515. const collectionSchema = objOf(collectionFields);
  23516. const collectionDataProcessor = arrOfObj([
  23517. value$1,
  23518. text,
  23519. icon
  23520. ]);
  23521. const colorInputFields = formComponentWithLabelFields;
  23522. const colorInputSchema = objOf(colorInputFields);
  23523. const colorInputDataProcessor = string;
  23524. const colorPickerFields = formComponentWithLabelFields;
  23525. const colorPickerSchema = objOf(colorPickerFields);
  23526. const colorPickerDataProcessor = string;
  23527. const customEditorFields = formComponentFields.concat([
  23528. defaultedString('tag', 'textarea'),
  23529. requiredString('scriptId'),
  23530. requiredString('scriptUrl'),
  23531. defaultedPostMsg('settings', undefined)
  23532. ]);
  23533. const customEditorFieldsOld = formComponentFields.concat([
  23534. defaultedString('tag', 'textarea'),
  23535. requiredFunction('init')
  23536. ]);
  23537. const customEditorSchema = valueOf(v => asRaw('customeditor.old', objOfOnly(customEditorFieldsOld), v).orThunk(() => asRaw('customeditor.new', objOfOnly(customEditorFields), v)));
  23538. const customEditorDataProcessor = string;
  23539. const dropZoneFields = formComponentWithLabelFields;
  23540. const dropZoneSchema = objOf(dropZoneFields);
  23541. const dropZoneDataProcessor = arrOfVal();
  23542. const createGridFields = itemsField => [
  23543. type,
  23544. requiredNumber('columns'),
  23545. itemsField
  23546. ];
  23547. const htmlPanelFields = [
  23548. type,
  23549. requiredString('html'),
  23550. defaultedStringEnum('presets', 'presentation', [
  23551. 'presentation',
  23552. 'document'
  23553. ])
  23554. ];
  23555. const htmlPanelSchema = objOf(htmlPanelFields);
  23556. const iframeFields = formComponentWithLabelFields.concat([
  23557. defaultedBoolean('sandboxed', true),
  23558. defaultedBoolean('transparent', true)
  23559. ]);
  23560. const iframeSchema = objOf(iframeFields);
  23561. const iframeDataProcessor = string;
  23562. const imagePreviewSchema = objOf(formComponentFields.concat([optionString('height')]));
  23563. const imagePreviewDataProcessor = objOf([
  23564. requiredString('url'),
  23565. optionNumber('zoom'),
  23566. optionNumber('cachedWidth'),
  23567. optionNumber('cachedHeight')
  23568. ]);
  23569. const inputFields = formComponentWithLabelFields.concat([
  23570. optionString('inputMode'),
  23571. optionString('placeholder'),
  23572. defaultedBoolean('maximized', false),
  23573. enabled
  23574. ]);
  23575. const inputSchema = objOf(inputFields);
  23576. const inputDataProcessor = string;
  23577. const createLabelFields = itemsField => [
  23578. type,
  23579. label,
  23580. itemsField
  23581. ];
  23582. const listBoxSingleItemFields = [
  23583. text,
  23584. value$1
  23585. ];
  23586. const listBoxNestedItemFields = [
  23587. text,
  23588. requiredArrayOf('items', thunkOf('items', () => listBoxItemSchema))
  23589. ];
  23590. const listBoxItemSchema = oneOf([
  23591. objOf(listBoxSingleItemFields),
  23592. objOf(listBoxNestedItemFields)
  23593. ]);
  23594. const listBoxFields = formComponentWithLabelFields.concat([
  23595. requiredArrayOf('items', listBoxItemSchema),
  23596. enabled
  23597. ]);
  23598. const listBoxSchema = objOf(listBoxFields);
  23599. const listBoxDataProcessor = string;
  23600. const selectBoxFields = formComponentWithLabelFields.concat([
  23601. requiredArrayOfObj('items', [
  23602. text,
  23603. value$1
  23604. ]),
  23605. defaultedNumber('size', 1),
  23606. enabled
  23607. ]);
  23608. const selectBoxSchema = objOf(selectBoxFields);
  23609. const selectBoxDataProcessor = string;
  23610. const sizeInputFields = formComponentWithLabelFields.concat([
  23611. defaultedBoolean('constrain', true),
  23612. enabled
  23613. ]);
  23614. const sizeInputSchema = objOf(sizeInputFields);
  23615. const sizeInputDataProcessor = objOf([
  23616. requiredString('width'),
  23617. requiredString('height')
  23618. ]);
  23619. const sliderFields = formComponentFields.concat([
  23620. label,
  23621. defaultedNumber('min', 0),
  23622. defaultedNumber('max', 0)
  23623. ]);
  23624. const sliderSchema = objOf(sliderFields);
  23625. const sliderInputDataProcessor = number;
  23626. const tableFields = [
  23627. type,
  23628. requiredArrayOf('header', string),
  23629. requiredArrayOf('cells', arrOf(string))
  23630. ];
  23631. const tableSchema = objOf(tableFields);
  23632. const textAreaFields = formComponentWithLabelFields.concat([
  23633. optionString('placeholder'),
  23634. defaultedBoolean('maximized', false),
  23635. enabled
  23636. ]);
  23637. const textAreaSchema = objOf(textAreaFields);
  23638. const textAreaDataProcessor = string;
  23639. const urlInputFields = formComponentWithLabelFields.concat([
  23640. defaultedStringEnum('filetype', 'file', [
  23641. 'image',
  23642. 'media',
  23643. 'file'
  23644. ]),
  23645. enabled
  23646. ]);
  23647. const urlInputSchema = objOf(urlInputFields);
  23648. const urlInputDataProcessor = objOf([
  23649. value$1,
  23650. defaultedMeta
  23651. ]);
  23652. 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)))));
  23653. const itemSchema = valueThunk(() => choose$2('type', {
  23654. alertbanner: alertBannerSchema,
  23655. bar: objOf(createBarFields(createItemsField('bar'))),
  23656. button: buttonSchema,
  23657. checkbox: checkboxSchema,
  23658. colorinput: colorInputSchema,
  23659. colorpicker: colorPickerSchema,
  23660. dropzone: dropZoneSchema,
  23661. grid: objOf(createGridFields(createItemsField('grid'))),
  23662. iframe: iframeSchema,
  23663. input: inputSchema,
  23664. listbox: listBoxSchema,
  23665. selectbox: selectBoxSchema,
  23666. sizeinput: sizeInputSchema,
  23667. slider: sliderSchema,
  23668. textarea: textAreaSchema,
  23669. urlinput: urlInputSchema,
  23670. customeditor: customEditorSchema,
  23671. htmlpanel: htmlPanelSchema,
  23672. imagepreview: imagePreviewSchema,
  23673. collection: collectionSchema,
  23674. label: objOf(createLabelFields(createItemsField('label'))),
  23675. table: tableSchema,
  23676. panel: panelSchema
  23677. }));
  23678. const panelFields = [
  23679. type,
  23680. defaulted('classes', []),
  23681. requiredArrayOf('items', itemSchema)
  23682. ];
  23683. const panelSchema = objOf(panelFields);
  23684. const tabFields = [
  23685. generatedName('tab'),
  23686. title,
  23687. requiredArrayOf('items', itemSchema)
  23688. ];
  23689. const tabPanelFields = [
  23690. type,
  23691. requiredArrayOfObj('tabs', tabFields)
  23692. ];
  23693. const tabPanelSchema = objOf(tabPanelFields);
  23694. const dialogButtonFields = dialogFooterButtonFields;
  23695. const dialogButtonSchema = dialogFooterButtonSchema;
  23696. const dialogSchema = objOf([
  23697. requiredString('title'),
  23698. requiredOf('body', choose$2('type', {
  23699. panel: panelSchema,
  23700. tabpanel: tabPanelSchema
  23701. })),
  23702. defaultedString('size', 'normal'),
  23703. requiredArrayOf('buttons', dialogButtonSchema),
  23704. defaulted('initialData', {}),
  23705. defaultedFunction('onAction', noop),
  23706. defaultedFunction('onChange', noop),
  23707. defaultedFunction('onSubmit', noop),
  23708. defaultedFunction('onClose', noop),
  23709. defaultedFunction('onCancel', noop),
  23710. defaultedFunction('onTabChange', noop)
  23711. ]);
  23712. const createDialog = spec => asRaw('dialog', dialogSchema, spec);
  23713. const urlDialogButtonSchema = objOf([
  23714. requiredStringEnum('type', [
  23715. 'cancel',
  23716. 'custom'
  23717. ]),
  23718. ...dialogButtonFields
  23719. ]);
  23720. const urlDialogSchema = objOf([
  23721. requiredString('title'),
  23722. requiredString('url'),
  23723. optionNumber('height'),
  23724. optionNumber('width'),
  23725. optionArrayOf('buttons', urlDialogButtonSchema),
  23726. defaultedFunction('onAction', noop),
  23727. defaultedFunction('onCancel', noop),
  23728. defaultedFunction('onClose', noop),
  23729. defaultedFunction('onMessage', noop)
  23730. ]);
  23731. const createUrlDialog = spec => asRaw('dialog', urlDialogSchema, spec);
  23732. const getAllObjects = obj => {
  23733. if (isObject(obj)) {
  23734. return [obj].concat(bind$3(values(obj), getAllObjects));
  23735. } else if (isArray(obj)) {
  23736. return bind$3(obj, getAllObjects);
  23737. } else {
  23738. return [];
  23739. }
  23740. };
  23741. const isNamedItem = obj => isString(obj.type) && isString(obj.name);
  23742. const dataProcessors = {
  23743. checkbox: checkboxDataProcessor,
  23744. colorinput: colorInputDataProcessor,
  23745. colorpicker: colorPickerDataProcessor,
  23746. dropzone: dropZoneDataProcessor,
  23747. input: inputDataProcessor,
  23748. iframe: iframeDataProcessor,
  23749. imagepreview: imagePreviewDataProcessor,
  23750. selectbox: selectBoxDataProcessor,
  23751. sizeinput: sizeInputDataProcessor,
  23752. slider: sliderInputDataProcessor,
  23753. listbox: listBoxDataProcessor,
  23754. size: sizeInputDataProcessor,
  23755. textarea: textAreaDataProcessor,
  23756. urlinput: urlInputDataProcessor,
  23757. customeditor: customEditorDataProcessor,
  23758. collection: collectionDataProcessor,
  23759. togglemenuitem: dialogToggleMenuItemDataProcessor
  23760. };
  23761. const getDataProcessor = item => Optional.from(dataProcessors[item.type]);
  23762. const getNamedItems = structure => filter$2(getAllObjects(structure), isNamedItem);
  23763. const createDataValidator = structure => {
  23764. const namedItems = getNamedItems(structure);
  23765. const fields = bind$3(namedItems, item => getDataProcessor(item).fold(() => [], schema => [requiredOf(item.name, schema)]));
  23766. return objOf(fields);
  23767. };
  23768. const extract = structure => {
  23769. const internalDialog = getOrDie(createDialog(structure));
  23770. const dataValidator = createDataValidator(structure);
  23771. const initialData = structure.initialData;
  23772. return {
  23773. internalDialog,
  23774. dataValidator,
  23775. initialData
  23776. };
  23777. };
  23778. const DialogManager = {
  23779. open: (factory, structure) => {
  23780. const extraction = extract(structure);
  23781. return factory(extraction.internalDialog, extraction.initialData, extraction.dataValidator);
  23782. },
  23783. openUrl: (factory, structure) => {
  23784. const internalDialog = getOrDie(createUrlDialog(structure));
  23785. return factory(internalDialog);
  23786. },
  23787. redial: structure => extract(structure)
  23788. };
  23789. const toValidValues = values => {
  23790. const errors = [];
  23791. const result = {};
  23792. each(values, (value, name) => {
  23793. value.fold(() => {
  23794. errors.push(name);
  23795. }, v => {
  23796. result[name] = v;
  23797. });
  23798. });
  23799. return errors.length > 0 ? Result.error(errors) : Result.value(result);
  23800. };
  23801. const renderBodyPanel = (spec, dialogData, backstage) => {
  23802. const memForm = record(Form.sketch(parts => ({
  23803. dom: {
  23804. tag: 'div',
  23805. classes: ['tox-form'].concat(spec.classes)
  23806. },
  23807. components: map$2(spec.items, item => interpretInForm(parts, item, dialogData, backstage))
  23808. })));
  23809. return {
  23810. dom: {
  23811. tag: 'div',
  23812. classes: ['tox-dialog__body']
  23813. },
  23814. components: [{
  23815. dom: {
  23816. tag: 'div',
  23817. classes: ['tox-dialog__body-content']
  23818. },
  23819. components: [memForm.asSpec()]
  23820. }],
  23821. behaviours: derive$1([
  23822. Keying.config({
  23823. mode: 'acyclic',
  23824. useTabstopAt: not(isPseudoStop)
  23825. }),
  23826. ComposingConfigs.memento(memForm),
  23827. RepresentingConfigs.memento(memForm, {
  23828. postprocess: formValue => toValidValues(formValue).fold(err => {
  23829. console.error(err);
  23830. return {};
  23831. }, identity)
  23832. })
  23833. ])
  23834. };
  23835. };
  23836. const factory$3 = (detail, _spec) => ({
  23837. uid: detail.uid,
  23838. dom: detail.dom,
  23839. components: detail.components,
  23840. events: events$a(detail.action),
  23841. behaviours: augment(detail.tabButtonBehaviours, [
  23842. Focusing.config({}),
  23843. Keying.config({
  23844. mode: 'execution',
  23845. useSpace: true,
  23846. useEnter: true
  23847. }),
  23848. Representing.config({
  23849. store: {
  23850. mode: 'memory',
  23851. initialValue: detail.value
  23852. }
  23853. })
  23854. ]),
  23855. domModification: detail.domModification
  23856. });
  23857. const TabButton = single({
  23858. name: 'TabButton',
  23859. configFields: [
  23860. defaulted('uid', undefined),
  23861. required$1('value'),
  23862. field$1('dom', 'dom', mergeWithThunk(() => ({
  23863. attributes: {
  23864. 'role': 'tab',
  23865. 'id': generate$6('aria'),
  23866. 'aria-selected': 'false'
  23867. }
  23868. })), anyValue()),
  23869. option$3('action'),
  23870. defaulted('domModification', {}),
  23871. field('tabButtonBehaviours', [
  23872. Focusing,
  23873. Keying,
  23874. Representing
  23875. ]),
  23876. required$1('view')
  23877. ],
  23878. factory: factory$3
  23879. });
  23880. const schema$1 = constant$1([
  23881. required$1('tabs'),
  23882. required$1('dom'),
  23883. defaulted('clickToDismiss', false),
  23884. field('tabbarBehaviours', [
  23885. Highlighting,
  23886. Keying
  23887. ]),
  23888. markers$1([
  23889. 'tabClass',
  23890. 'selectedClass'
  23891. ])
  23892. ]);
  23893. const tabsPart = group({
  23894. factory: TabButton,
  23895. name: 'tabs',
  23896. unit: 'tab',
  23897. overrides: barDetail => {
  23898. const dismissTab$1 = (tabbar, button) => {
  23899. Highlighting.dehighlight(tabbar, button);
  23900. emitWith(tabbar, dismissTab(), {
  23901. tabbar,
  23902. button
  23903. });
  23904. };
  23905. const changeTab$1 = (tabbar, button) => {
  23906. Highlighting.highlight(tabbar, button);
  23907. emitWith(tabbar, changeTab(), {
  23908. tabbar,
  23909. button
  23910. });
  23911. };
  23912. return {
  23913. action: button => {
  23914. const tabbar = button.getSystem().getByUid(barDetail.uid).getOrDie();
  23915. const activeButton = Highlighting.isHighlighted(tabbar, button);
  23916. const response = (() => {
  23917. if (activeButton && barDetail.clickToDismiss) {
  23918. return dismissTab$1;
  23919. } else if (!activeButton) {
  23920. return changeTab$1;
  23921. } else {
  23922. return noop;
  23923. }
  23924. })();
  23925. response(tabbar, button);
  23926. },
  23927. domModification: { classes: [barDetail.markers.tabClass] }
  23928. };
  23929. }
  23930. });
  23931. const parts$1 = constant$1([tabsPart]);
  23932. const factory$2 = (detail, components, _spec, _externals) => ({
  23933. 'uid': detail.uid,
  23934. 'dom': detail.dom,
  23935. components,
  23936. 'debug.sketcher': 'Tabbar',
  23937. 'domModification': { attributes: { role: 'tablist' } },
  23938. 'behaviours': augment(detail.tabbarBehaviours, [
  23939. Highlighting.config({
  23940. highlightClass: detail.markers.selectedClass,
  23941. itemClass: detail.markers.tabClass,
  23942. onHighlight: (tabbar, tab) => {
  23943. set$9(tab.element, 'aria-selected', 'true');
  23944. },
  23945. onDehighlight: (tabbar, tab) => {
  23946. set$9(tab.element, 'aria-selected', 'false');
  23947. }
  23948. }),
  23949. Keying.config({
  23950. mode: 'flow',
  23951. getInitial: tabbar => {
  23952. return Highlighting.getHighlighted(tabbar).map(tab => tab.element);
  23953. },
  23954. selector: '.' + detail.markers.tabClass,
  23955. executeOnMove: true
  23956. })
  23957. ])
  23958. });
  23959. const Tabbar = composite({
  23960. name: 'Tabbar',
  23961. configFields: schema$1(),
  23962. partFields: parts$1(),
  23963. factory: factory$2
  23964. });
  23965. const factory$1 = (detail, _spec) => ({
  23966. uid: detail.uid,
  23967. dom: detail.dom,
  23968. behaviours: augment(detail.tabviewBehaviours, [Replacing.config({})]),
  23969. domModification: { attributes: { role: 'tabpanel' } }
  23970. });
  23971. const Tabview = single({
  23972. name: 'Tabview',
  23973. configFields: [field('tabviewBehaviours', [Replacing])],
  23974. factory: factory$1
  23975. });
  23976. const schema = constant$1([
  23977. defaulted('selectFirst', true),
  23978. onHandler('onChangeTab'),
  23979. onHandler('onDismissTab'),
  23980. defaulted('tabs', []),
  23981. field('tabSectionBehaviours', [])
  23982. ]);
  23983. const barPart = required({
  23984. factory: Tabbar,
  23985. schema: [
  23986. required$1('dom'),
  23987. requiredObjOf('markers', [
  23988. required$1('tabClass'),
  23989. required$1('selectedClass')
  23990. ])
  23991. ],
  23992. name: 'tabbar',
  23993. defaults: detail => {
  23994. return { tabs: detail.tabs };
  23995. }
  23996. });
  23997. const viewPart = required({
  23998. factory: Tabview,
  23999. name: 'tabview'
  24000. });
  24001. const parts = constant$1([
  24002. barPart,
  24003. viewPart
  24004. ]);
  24005. const factory = (detail, components, _spec, _externals) => {
  24006. const changeTab$1 = button => {
  24007. const tabValue = Representing.getValue(button);
  24008. getPart(button, detail, 'tabview').each(tabview => {
  24009. const tabWithValue = find$5(detail.tabs, t => t.value === tabValue);
  24010. tabWithValue.each(tabData => {
  24011. const panel = tabData.view();
  24012. getOpt(button.element, 'id').each(id => {
  24013. set$9(tabview.element, 'aria-labelledby', id);
  24014. });
  24015. Replacing.set(tabview, panel);
  24016. detail.onChangeTab(tabview, button, panel);
  24017. });
  24018. });
  24019. };
  24020. const changeTabBy = (section, byPred) => {
  24021. getPart(section, detail, 'tabbar').each(tabbar => {
  24022. byPred(tabbar).each(emitExecute);
  24023. });
  24024. };
  24025. return {
  24026. uid: detail.uid,
  24027. dom: detail.dom,
  24028. components,
  24029. behaviours: get$3(detail.tabSectionBehaviours),
  24030. events: derive$2(flatten([
  24031. detail.selectFirst ? [runOnAttached((section, _simulatedEvent) => {
  24032. changeTabBy(section, Highlighting.getFirst);
  24033. })] : [],
  24034. [
  24035. run$1(changeTab(), (section, simulatedEvent) => {
  24036. const button = simulatedEvent.event.button;
  24037. changeTab$1(button);
  24038. }),
  24039. run$1(dismissTab(), (section, simulatedEvent) => {
  24040. const button = simulatedEvent.event.button;
  24041. detail.onDismissTab(section, button);
  24042. })
  24043. ]
  24044. ])),
  24045. apis: {
  24046. getViewItems: section => {
  24047. return getPart(section, detail, 'tabview').map(tabview => Replacing.contents(tabview)).getOr([]);
  24048. },
  24049. showTab: (section, tabKey) => {
  24050. const getTabIfNotActive = tabbar => {
  24051. const candidates = Highlighting.getCandidates(tabbar);
  24052. const optTab = find$5(candidates, c => Representing.getValue(c) === tabKey);
  24053. return optTab.filter(tab => !Highlighting.isHighlighted(tabbar, tab));
  24054. };
  24055. changeTabBy(section, getTabIfNotActive);
  24056. }
  24057. }
  24058. };
  24059. };
  24060. const TabSection = composite({
  24061. name: 'TabSection',
  24062. configFields: schema(),
  24063. partFields: parts(),
  24064. factory,
  24065. apis: {
  24066. getViewItems: (apis, component) => apis.getViewItems(component),
  24067. showTab: (apis, component, tabKey) => {
  24068. apis.showTab(component, tabKey);
  24069. }
  24070. }
  24071. });
  24072. const measureHeights = (allTabs, tabview, tabviewComp) => map$2(allTabs, (_tab, i) => {
  24073. Replacing.set(tabviewComp, allTabs[i].view());
  24074. const rect = tabview.dom.getBoundingClientRect();
  24075. Replacing.set(tabviewComp, []);
  24076. return rect.height;
  24077. });
  24078. const getMaxHeight = heights => head(sort(heights, (a, b) => {
  24079. if (a > b) {
  24080. return -1;
  24081. } else if (a < b) {
  24082. return +1;
  24083. } else {
  24084. return 0;
  24085. }
  24086. }));
  24087. const getMaxTabviewHeight = (dialog, tabview, tablist) => {
  24088. const documentElement$1 = documentElement(dialog).dom;
  24089. const rootElm = ancestor(dialog, '.tox-dialog-wrap').getOr(dialog);
  24090. const isFixed = get$e(rootElm, 'position') === 'fixed';
  24091. let maxHeight;
  24092. if (isFixed) {
  24093. maxHeight = Math.max(documentElement$1.clientHeight, window.innerHeight);
  24094. } else {
  24095. maxHeight = Math.max(documentElement$1.offsetHeight, documentElement$1.scrollHeight);
  24096. }
  24097. const tabviewHeight = get$d(tabview);
  24098. const isTabListBeside = tabview.dom.offsetLeft >= tablist.dom.offsetLeft + get$c(tablist);
  24099. const currentTabHeight = isTabListBeside ? Math.max(get$d(tablist), tabviewHeight) : tabviewHeight;
  24100. const dialogTopMargin = parseInt(get$e(dialog, 'margin-top'), 10) || 0;
  24101. const dialogBottomMargin = parseInt(get$e(dialog, 'margin-bottom'), 10) || 0;
  24102. const dialogHeight = get$d(dialog) + dialogTopMargin + dialogBottomMargin;
  24103. const chromeHeight = dialogHeight - currentTabHeight;
  24104. return maxHeight - chromeHeight;
  24105. };
  24106. const showTab = (allTabs, comp) => {
  24107. head(allTabs).each(tab => TabSection.showTab(comp, tab.value));
  24108. };
  24109. const setTabviewHeight = (tabview, height) => {
  24110. set$8(tabview, 'height', height + 'px');
  24111. set$8(tabview, 'flex-basis', height + 'px');
  24112. };
  24113. const updateTabviewHeight = (dialogBody, tabview, maxTabHeight) => {
  24114. ancestor(dialogBody, '[role="dialog"]').each(dialog => {
  24115. descendant(dialog, '[role="tablist"]').each(tablist => {
  24116. maxTabHeight.get().map(height => {
  24117. set$8(tabview, 'height', '0');
  24118. set$8(tabview, 'flex-basis', '0');
  24119. return Math.min(height, getMaxTabviewHeight(dialog, tabview, tablist));
  24120. }).each(height => {
  24121. setTabviewHeight(tabview, height);
  24122. });
  24123. });
  24124. });
  24125. };
  24126. const getTabview = dialog => descendant(dialog, '[role="tabpanel"]');
  24127. const setMode = allTabs => {
  24128. const smartTabHeight = (() => {
  24129. const maxTabHeight = value$2();
  24130. const extraEvents = [
  24131. runOnAttached(comp => {
  24132. const dialog = comp.element;
  24133. getTabview(dialog).each(tabview => {
  24134. set$8(tabview, 'visibility', 'hidden');
  24135. comp.getSystem().getByDom(tabview).toOptional().each(tabviewComp => {
  24136. const heights = measureHeights(allTabs, tabview, tabviewComp);
  24137. const maxTabHeightOpt = getMaxHeight(heights);
  24138. maxTabHeightOpt.fold(maxTabHeight.clear, maxTabHeight.set);
  24139. });
  24140. updateTabviewHeight(dialog, tabview, maxTabHeight);
  24141. remove$6(tabview, 'visibility');
  24142. showTab(allTabs, comp);
  24143. requestAnimationFrame(() => {
  24144. updateTabviewHeight(dialog, tabview, maxTabHeight);
  24145. });
  24146. });
  24147. }),
  24148. run$1(windowResize(), comp => {
  24149. const dialog = comp.element;
  24150. getTabview(dialog).each(tabview => {
  24151. updateTabviewHeight(dialog, tabview, maxTabHeight);
  24152. });
  24153. }),
  24154. run$1(formResizeEvent, (comp, _se) => {
  24155. const dialog = comp.element;
  24156. getTabview(dialog).each(tabview => {
  24157. const oldFocus = active$1(getRootNode(tabview));
  24158. set$8(tabview, 'visibility', 'hidden');
  24159. const oldHeight = getRaw(tabview, 'height').map(h => parseInt(h, 10));
  24160. remove$6(tabview, 'height');
  24161. remove$6(tabview, 'flex-basis');
  24162. const newHeight = tabview.dom.getBoundingClientRect().height;
  24163. const hasGrown = oldHeight.forall(h => newHeight > h);
  24164. if (hasGrown) {
  24165. maxTabHeight.set(newHeight);
  24166. updateTabviewHeight(dialog, tabview, maxTabHeight);
  24167. } else {
  24168. oldHeight.each(h => {
  24169. setTabviewHeight(tabview, h);
  24170. });
  24171. }
  24172. remove$6(tabview, 'visibility');
  24173. oldFocus.each(focus$3);
  24174. });
  24175. })
  24176. ];
  24177. const selectFirst = false;
  24178. return {
  24179. extraEvents,
  24180. selectFirst
  24181. };
  24182. })();
  24183. const naiveTabHeight = (() => {
  24184. const extraEvents = [];
  24185. const selectFirst = true;
  24186. return {
  24187. extraEvents,
  24188. selectFirst
  24189. };
  24190. })();
  24191. return {
  24192. smartTabHeight,
  24193. naiveTabHeight
  24194. };
  24195. };
  24196. const SendDataToSectionChannel = 'send-data-to-section';
  24197. const SendDataToViewChannel = 'send-data-to-view';
  24198. const renderTabPanel = (spec, dialogData, backstage) => {
  24199. const storedValue = Cell({});
  24200. const updateDataWithForm = form => {
  24201. const formData = Representing.getValue(form);
  24202. const validData = toValidValues(formData).getOr({});
  24203. const currentData = storedValue.get();
  24204. const newData = deepMerge(currentData, validData);
  24205. storedValue.set(newData);
  24206. };
  24207. const setDataOnForm = form => {
  24208. const tabData = storedValue.get();
  24209. Representing.setValue(form, tabData);
  24210. };
  24211. const oldTab = Cell(null);
  24212. const allTabs = map$2(spec.tabs, tab => {
  24213. return {
  24214. value: tab.name,
  24215. dom: {
  24216. tag: 'div',
  24217. classes: ['tox-dialog__body-nav-item']
  24218. },
  24219. components: [text$1(backstage.shared.providers.translate(tab.title))],
  24220. view: () => {
  24221. return [Form.sketch(parts => ({
  24222. dom: {
  24223. tag: 'div',
  24224. classes: ['tox-form']
  24225. },
  24226. components: map$2(tab.items, item => interpretInForm(parts, item, dialogData, backstage)),
  24227. formBehaviours: derive$1([
  24228. Keying.config({
  24229. mode: 'acyclic',
  24230. useTabstopAt: not(isPseudoStop)
  24231. }),
  24232. config('TabView.form.events', [
  24233. runOnAttached(setDataOnForm),
  24234. runOnDetached(updateDataWithForm)
  24235. ]),
  24236. Receiving.config({
  24237. channels: wrapAll([
  24238. {
  24239. key: SendDataToSectionChannel,
  24240. value: { onReceive: updateDataWithForm }
  24241. },
  24242. {
  24243. key: SendDataToViewChannel,
  24244. value: { onReceive: setDataOnForm }
  24245. }
  24246. ])
  24247. })
  24248. ])
  24249. }))];
  24250. }
  24251. };
  24252. });
  24253. const tabMode = setMode(allTabs).smartTabHeight;
  24254. return TabSection.sketch({
  24255. dom: {
  24256. tag: 'div',
  24257. classes: ['tox-dialog__body']
  24258. },
  24259. onChangeTab: (section, button, _viewItems) => {
  24260. const name = Representing.getValue(button);
  24261. emitWith(section, formTabChangeEvent, {
  24262. name,
  24263. oldName: oldTab.get()
  24264. });
  24265. oldTab.set(name);
  24266. },
  24267. tabs: allTabs,
  24268. components: [
  24269. TabSection.parts.tabbar({
  24270. dom: {
  24271. tag: 'div',
  24272. classes: ['tox-dialog__body-nav']
  24273. },
  24274. components: [Tabbar.parts.tabs({})],
  24275. markers: {
  24276. tabClass: 'tox-tab',
  24277. selectedClass: 'tox-dialog__body-nav-item--active'
  24278. },
  24279. tabbarBehaviours: derive$1([Tabstopping.config({})])
  24280. }),
  24281. TabSection.parts.tabview({
  24282. dom: {
  24283. tag: 'div',
  24284. classes: ['tox-dialog__body-content']
  24285. }
  24286. })
  24287. ],
  24288. selectFirst: tabMode.selectFirst,
  24289. tabSectionBehaviours: derive$1([
  24290. config('tabpanel', tabMode.extraEvents),
  24291. Keying.config({ mode: 'acyclic' }),
  24292. Composing.config({ find: comp => head(TabSection.getViewItems(comp)) }),
  24293. RepresentingConfigs.withComp(Optional.none(), tsection => {
  24294. tsection.getSystem().broadcastOn([SendDataToSectionChannel], {});
  24295. return storedValue.get();
  24296. }, (tsection, value) => {
  24297. storedValue.set(value);
  24298. tsection.getSystem().broadcastOn([SendDataToViewChannel], {});
  24299. })
  24300. ])
  24301. });
  24302. };
  24303. const dialogChannel = generate$6('update-dialog');
  24304. const titleChannel = generate$6('update-title');
  24305. const bodyChannel = generate$6('update-body');
  24306. const footerChannel = generate$6('update-footer');
  24307. const bodySendMessageChannel = generate$6('body-send-message');
  24308. const renderBody = (spec, dialogId, contentId, backstage, ariaAttrs) => {
  24309. const renderComponents = incoming => {
  24310. const body = incoming.body;
  24311. switch (body.type) {
  24312. case 'tabpanel': {
  24313. return [renderTabPanel(body, incoming.initialData, backstage)];
  24314. }
  24315. default: {
  24316. return [renderBodyPanel(body, incoming.initialData, backstage)];
  24317. }
  24318. }
  24319. };
  24320. const updateState = (_comp, incoming) => Optional.some({ isTabPanel: () => incoming.body.type === 'tabpanel' });
  24321. const ariaAttributes = { 'aria-live': 'polite' };
  24322. return {
  24323. dom: {
  24324. tag: 'div',
  24325. classes: ['tox-dialog__content-js'],
  24326. attributes: {
  24327. ...contentId.map(x => ({ id: x })).getOr({}),
  24328. ...ariaAttrs ? ariaAttributes : {}
  24329. }
  24330. },
  24331. components: [],
  24332. behaviours: derive$1([
  24333. ComposingConfigs.childAt(0),
  24334. Reflecting.config({
  24335. channel: `${ bodyChannel }-${ dialogId }`,
  24336. updateState,
  24337. renderComponents,
  24338. initialData: spec
  24339. })
  24340. ])
  24341. };
  24342. };
  24343. const renderInlineBody = (spec, dialogId, contentId, backstage, ariaAttrs) => renderBody(spec, dialogId, Optional.some(contentId), backstage, ariaAttrs);
  24344. const renderModalBody = (spec, dialogId, backstage) => {
  24345. const bodySpec = renderBody(spec, dialogId, Optional.none(), backstage, false);
  24346. return ModalDialog.parts.body(bodySpec);
  24347. };
  24348. const renderIframeBody = spec => {
  24349. const bodySpec = {
  24350. dom: {
  24351. tag: 'div',
  24352. classes: ['tox-dialog__content-js']
  24353. },
  24354. components: [{
  24355. dom: {
  24356. tag: 'div',
  24357. classes: ['tox-dialog__body-iframe']
  24358. },
  24359. components: [craft({
  24360. dom: {
  24361. tag: 'iframe',
  24362. attributes: { src: spec.url }
  24363. },
  24364. behaviours: derive$1([
  24365. Tabstopping.config({}),
  24366. Focusing.config({})
  24367. ])
  24368. })]
  24369. }],
  24370. behaviours: derive$1([Keying.config({
  24371. mode: 'acyclic',
  24372. useTabstopAt: not(isPseudoStop)
  24373. })])
  24374. };
  24375. return ModalDialog.parts.body(bodySpec);
  24376. };
  24377. const isTouch = global$5.deviceType.isTouch();
  24378. const hiddenHeader = (title, close) => ({
  24379. dom: {
  24380. tag: 'div',
  24381. styles: { display: 'none' },
  24382. classes: ['tox-dialog__header']
  24383. },
  24384. components: [
  24385. title,
  24386. close
  24387. ]
  24388. });
  24389. const pClose = (onClose, providersBackstage) => ModalDialog.parts.close(Button.sketch({
  24390. dom: {
  24391. tag: 'button',
  24392. classes: [
  24393. 'tox-button',
  24394. 'tox-button--icon',
  24395. 'tox-button--naked'
  24396. ],
  24397. attributes: {
  24398. 'type': 'button',
  24399. 'aria-label': providersBackstage.translate('Close')
  24400. }
  24401. },
  24402. action: onClose,
  24403. buttonBehaviours: derive$1([Tabstopping.config({})])
  24404. }));
  24405. const pUntitled = () => ModalDialog.parts.title({
  24406. dom: {
  24407. tag: 'div',
  24408. classes: ['tox-dialog__title'],
  24409. innerHtml: '',
  24410. styles: { display: 'none' }
  24411. }
  24412. });
  24413. const pBodyMessage = (message, providersBackstage) => ModalDialog.parts.body({
  24414. dom: {
  24415. tag: 'div',
  24416. classes: ['tox-dialog__body']
  24417. },
  24418. components: [{
  24419. dom: {
  24420. tag: 'div',
  24421. classes: ['tox-dialog__body-content']
  24422. },
  24423. components: [{ dom: fromHtml(`<p>${ providersBackstage.translate(message) }</p>`) }]
  24424. }]
  24425. });
  24426. const pFooter = buttons => ModalDialog.parts.footer({
  24427. dom: {
  24428. tag: 'div',
  24429. classes: ['tox-dialog__footer']
  24430. },
  24431. components: buttons
  24432. });
  24433. const pFooterGroup = (startButtons, endButtons) => [
  24434. Container.sketch({
  24435. dom: {
  24436. tag: 'div',
  24437. classes: ['tox-dialog__footer-start']
  24438. },
  24439. components: startButtons
  24440. }),
  24441. Container.sketch({
  24442. dom: {
  24443. tag: 'div',
  24444. classes: ['tox-dialog__footer-end']
  24445. },
  24446. components: endButtons
  24447. })
  24448. ];
  24449. const renderDialog$1 = spec => {
  24450. const dialogClass = 'tox-dialog';
  24451. const blockerClass = dialogClass + '-wrap';
  24452. const blockerBackdropClass = blockerClass + '__backdrop';
  24453. const scrollLockClass = dialogClass + '__disable-scroll';
  24454. return ModalDialog.sketch({
  24455. lazySink: spec.lazySink,
  24456. onEscape: comp => {
  24457. spec.onEscape(comp);
  24458. return Optional.some(true);
  24459. },
  24460. useTabstopAt: elem => !isPseudoStop(elem),
  24461. dom: {
  24462. tag: 'div',
  24463. classes: [dialogClass].concat(spec.extraClasses),
  24464. styles: {
  24465. position: 'relative',
  24466. ...spec.extraStyles
  24467. }
  24468. },
  24469. components: [
  24470. spec.header,
  24471. spec.body,
  24472. ...spec.footer.toArray()
  24473. ],
  24474. parts: {
  24475. blocker: {
  24476. dom: fromHtml(`<div class="${ blockerClass }"></div>`),
  24477. components: [{
  24478. dom: {
  24479. tag: 'div',
  24480. classes: isTouch ? [
  24481. blockerBackdropClass,
  24482. blockerBackdropClass + '--opaque'
  24483. ] : [blockerBackdropClass]
  24484. }
  24485. }]
  24486. }
  24487. },
  24488. dragBlockClass: blockerClass,
  24489. modalBehaviours: derive$1([
  24490. Focusing.config({}),
  24491. config('dialog-events', spec.dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
  24492. Keying.focusIn(comp);
  24493. })])),
  24494. config('scroll-lock', [
  24495. runOnAttached(() => {
  24496. add$2(body(), scrollLockClass);
  24497. }),
  24498. runOnDetached(() => {
  24499. remove$2(body(), scrollLockClass);
  24500. })
  24501. ]),
  24502. ...spec.extraBehaviours
  24503. ]),
  24504. eventOrder: {
  24505. [execute$5()]: ['dialog-events'],
  24506. [attachedToDom()]: [
  24507. 'scroll-lock',
  24508. 'dialog-events',
  24509. 'alloy.base.behaviour'
  24510. ],
  24511. [detachedFromDom()]: [
  24512. 'alloy.base.behaviour',
  24513. 'dialog-events',
  24514. 'scroll-lock'
  24515. ],
  24516. ...spec.eventOrder
  24517. }
  24518. });
  24519. };
  24520. const renderClose = providersBackstage => Button.sketch({
  24521. dom: {
  24522. tag: 'button',
  24523. classes: [
  24524. 'tox-button',
  24525. 'tox-button--icon',
  24526. 'tox-button--naked'
  24527. ],
  24528. attributes: {
  24529. 'type': 'button',
  24530. 'aria-label': providersBackstage.translate('Close'),
  24531. 'title': providersBackstage.translate('Close')
  24532. }
  24533. },
  24534. components: [render$3('close', {
  24535. tag: 'div',
  24536. classes: ['tox-icon']
  24537. }, providersBackstage.icons)],
  24538. action: comp => {
  24539. emit(comp, formCancelEvent);
  24540. }
  24541. });
  24542. const renderTitle = (spec, dialogId, titleId, providersBackstage) => {
  24543. const renderComponents = data => [text$1(providersBackstage.translate(data.title))];
  24544. return {
  24545. dom: {
  24546. tag: 'div',
  24547. classes: ['tox-dialog__title'],
  24548. attributes: { ...titleId.map(x => ({ id: x })).getOr({}) }
  24549. },
  24550. components: [],
  24551. behaviours: derive$1([Reflecting.config({
  24552. channel: `${ titleChannel }-${ dialogId }`,
  24553. initialData: spec,
  24554. renderComponents
  24555. })])
  24556. };
  24557. };
  24558. const renderDragHandle = () => ({ dom: fromHtml('<div class="tox-dialog__draghandle"></div>') });
  24559. const renderInlineHeader = (spec, dialogId, titleId, providersBackstage) => Container.sketch({
  24560. dom: fromHtml('<div class="tox-dialog__header"></div>'),
  24561. components: [
  24562. renderTitle(spec, dialogId, Optional.some(titleId), providersBackstage),
  24563. renderDragHandle(),
  24564. renderClose(providersBackstage)
  24565. ],
  24566. containerBehaviours: derive$1([Dragging.config({
  24567. mode: 'mouse',
  24568. blockerClass: 'blocker',
  24569. getTarget: handle => {
  24570. return closest$1(handle, '[role="dialog"]').getOrDie();
  24571. },
  24572. snaps: {
  24573. getSnapPoints: () => [],
  24574. leftAttr: 'data-drag-left',
  24575. topAttr: 'data-drag-top'
  24576. }
  24577. })])
  24578. });
  24579. const renderModalHeader = (spec, dialogId, providersBackstage) => {
  24580. const pTitle = ModalDialog.parts.title(renderTitle(spec, dialogId, Optional.none(), providersBackstage));
  24581. const pHandle = ModalDialog.parts.draghandle(renderDragHandle());
  24582. const pClose = ModalDialog.parts.close(renderClose(providersBackstage));
  24583. const components = [pTitle].concat(spec.draggable ? [pHandle] : []).concat([pClose]);
  24584. return Container.sketch({
  24585. dom: fromHtml('<div class="tox-dialog__header"></div>'),
  24586. components
  24587. });
  24588. };
  24589. const getHeader = (title, dialogId, backstage) => renderModalHeader({
  24590. title: backstage.shared.providers.translate(title),
  24591. draggable: backstage.dialog.isDraggableModal()
  24592. }, dialogId, backstage.shared.providers);
  24593. const getBusySpec = (message, bs, providers) => ({
  24594. dom: {
  24595. tag: 'div',
  24596. classes: ['tox-dialog__busy-spinner'],
  24597. attributes: { 'aria-label': providers.translate(message) },
  24598. styles: {
  24599. left: '0px',
  24600. right: '0px',
  24601. bottom: '0px',
  24602. top: '0px',
  24603. position: 'absolute'
  24604. }
  24605. },
  24606. behaviours: bs,
  24607. components: [{ dom: fromHtml('<div class="tox-spinner"><div></div><div></div><div></div></div>') }]
  24608. });
  24609. const getEventExtras = (lazyDialog, providers, extra) => ({
  24610. onClose: () => extra.closeWindow(),
  24611. onBlock: blockEvent => {
  24612. ModalDialog.setBusy(lazyDialog(), (_comp, bs) => getBusySpec(blockEvent.message, bs, providers));
  24613. },
  24614. onUnblock: () => {
  24615. ModalDialog.setIdle(lazyDialog());
  24616. }
  24617. });
  24618. const renderModalDialog = (spec, initialData, dialogEvents, backstage) => {
  24619. const updateState = (_comp, incoming) => Optional.some(incoming);
  24620. return build$1(renderDialog$1({
  24621. ...spec,
  24622. lazySink: backstage.shared.getSink,
  24623. extraBehaviours: [
  24624. Reflecting.config({
  24625. channel: `${ dialogChannel }-${ spec.id }`,
  24626. updateState,
  24627. initialData
  24628. }),
  24629. RepresentingConfigs.memory({}),
  24630. ...spec.extraBehaviours
  24631. ],
  24632. onEscape: comp => {
  24633. emit(comp, formCancelEvent);
  24634. },
  24635. dialogEvents,
  24636. eventOrder: {
  24637. [receive()]: [
  24638. Reflecting.name(),
  24639. Receiving.name()
  24640. ],
  24641. [attachedToDom()]: [
  24642. 'scroll-lock',
  24643. Reflecting.name(),
  24644. 'messages',
  24645. 'dialog-events',
  24646. 'alloy.base.behaviour'
  24647. ],
  24648. [detachedFromDom()]: [
  24649. 'alloy.base.behaviour',
  24650. 'dialog-events',
  24651. 'messages',
  24652. Reflecting.name(),
  24653. 'scroll-lock'
  24654. ]
  24655. }
  24656. }));
  24657. };
  24658. const mapMenuButtons = buttons => {
  24659. const mapItems = button => {
  24660. const items = map$2(button.items, item => {
  24661. const cell = Cell(false);
  24662. return {
  24663. ...item,
  24664. storage: cell
  24665. };
  24666. });
  24667. return {
  24668. ...button,
  24669. items
  24670. };
  24671. };
  24672. return map$2(buttons, button => {
  24673. if (button.type === 'menu') {
  24674. return mapItems(button);
  24675. }
  24676. return button;
  24677. });
  24678. };
  24679. const extractCellsToObject = buttons => foldl(buttons, (acc, button) => {
  24680. if (button.type === 'menu') {
  24681. const menuButton = button;
  24682. return foldl(menuButton.items, (innerAcc, item) => {
  24683. innerAcc[item.name] = item.storage;
  24684. return innerAcc;
  24685. }, acc);
  24686. }
  24687. return acc;
  24688. }, {});
  24689. const initCommonEvents = (fireApiEvent, extras) => [
  24690. runWithTarget(focusin(), onFocus),
  24691. fireApiEvent(formCloseEvent, (_api, spec) => {
  24692. extras.onClose();
  24693. spec.onClose();
  24694. }),
  24695. fireApiEvent(formCancelEvent, (api, spec, _event, self) => {
  24696. spec.onCancel(api);
  24697. emit(self, formCloseEvent);
  24698. }),
  24699. run$1(formUnblockEvent, (_c, _se) => extras.onUnblock()),
  24700. run$1(formBlockEvent, (_c, se) => extras.onBlock(se.event))
  24701. ];
  24702. const initUrlDialog = (getInstanceApi, extras) => {
  24703. const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
  24704. withSpec(c, (spec, _c) => {
  24705. f(getInstanceApi(), spec, se.event, c);
  24706. });
  24707. });
  24708. const withSpec = (c, f) => {
  24709. Reflecting.getState(c).get().each(currentDialog => {
  24710. f(currentDialog, c);
  24711. });
  24712. };
  24713. return [
  24714. ...initCommonEvents(fireApiEvent, extras),
  24715. fireApiEvent(formActionEvent, (api, spec, event) => {
  24716. spec.onAction(api, { name: event.name });
  24717. })
  24718. ];
  24719. };
  24720. const initDialog = (getInstanceApi, extras, getSink) => {
  24721. const fireApiEvent = (eventName, f) => run$1(eventName, (c, se) => {
  24722. withSpec(c, (spec, _c) => {
  24723. f(getInstanceApi(), spec, se.event, c);
  24724. });
  24725. });
  24726. const withSpec = (c, f) => {
  24727. Reflecting.getState(c).get().each(currentDialogInit => {
  24728. f(currentDialogInit.internalDialog, c);
  24729. });
  24730. };
  24731. return [
  24732. ...initCommonEvents(fireApiEvent, extras),
  24733. fireApiEvent(formSubmitEvent, (api, spec) => spec.onSubmit(api)),
  24734. fireApiEvent(formChangeEvent, (api, spec, event) => {
  24735. spec.onChange(api, { name: event.name });
  24736. }),
  24737. fireApiEvent(formActionEvent, (api, spec, event, component) => {
  24738. const focusIn = () => Keying.focusIn(component);
  24739. const isDisabled = focused => has$1(focused, 'disabled') || getOpt(focused, 'aria-disabled').exists(val => val === 'true');
  24740. const rootNode = getRootNode(component.element);
  24741. const current = active$1(rootNode);
  24742. spec.onAction(api, {
  24743. name: event.name,
  24744. value: event.value
  24745. });
  24746. active$1(rootNode).fold(focusIn, focused => {
  24747. if (isDisabled(focused)) {
  24748. focusIn();
  24749. } else if (current.exists(cur => contains(focused, cur) && isDisabled(cur))) {
  24750. focusIn();
  24751. } else {
  24752. getSink().toOptional().filter(sink => !contains(sink.element, focused)).each(focusIn);
  24753. }
  24754. });
  24755. }),
  24756. fireApiEvent(formTabChangeEvent, (api, spec, event) => {
  24757. spec.onTabChange(api, {
  24758. newTabName: event.name,
  24759. oldTabName: event.oldName
  24760. });
  24761. }),
  24762. runOnDetached(component => {
  24763. const api = getInstanceApi();
  24764. Representing.setValue(component, api.getData());
  24765. })
  24766. ];
  24767. };
  24768. const SilverDialogEvents = {
  24769. initUrlDialog,
  24770. initDialog
  24771. };
  24772. const makeButton = (button, backstage) => renderFooterButton(button, button.type, backstage);
  24773. const lookup = (compInSystem, footerButtons, buttonName) => find$5(footerButtons, button => button.name === buttonName).bind(memButton => memButton.memento.getOpt(compInSystem));
  24774. const renderComponents = (_data, state) => {
  24775. const footerButtons = state.map(s => s.footerButtons).getOr([]);
  24776. const buttonGroups = partition$3(footerButtons, button => button.align === 'start');
  24777. const makeGroup = (edge, buttons) => Container.sketch({
  24778. dom: {
  24779. tag: 'div',
  24780. classes: [`tox-dialog__footer-${ edge }`]
  24781. },
  24782. components: map$2(buttons, button => button.memento.asSpec())
  24783. });
  24784. const startButtons = makeGroup('start', buttonGroups.pass);
  24785. const endButtons = makeGroup('end', buttonGroups.fail);
  24786. return [
  24787. startButtons,
  24788. endButtons
  24789. ];
  24790. };
  24791. const renderFooter = (initSpec, dialogId, backstage) => {
  24792. const updateState = (comp, data) => {
  24793. const footerButtons = map$2(data.buttons, button => {
  24794. const memButton = record(makeButton(button, backstage));
  24795. return {
  24796. name: button.name,
  24797. align: button.align,
  24798. memento: memButton
  24799. };
  24800. });
  24801. const lookupByName = buttonName => lookup(comp, footerButtons, buttonName);
  24802. return Optional.some({
  24803. lookupByName,
  24804. footerButtons
  24805. });
  24806. };
  24807. return {
  24808. dom: fromHtml('<div class="tox-dialog__footer"></div>'),
  24809. components: [],
  24810. behaviours: derive$1([Reflecting.config({
  24811. channel: `${ footerChannel }-${ dialogId }`,
  24812. initialData: initSpec,
  24813. updateState,
  24814. renderComponents
  24815. })])
  24816. };
  24817. };
  24818. const renderInlineFooter = (initSpec, dialogId, backstage) => renderFooter(initSpec, dialogId, backstage);
  24819. const renderModalFooter = (initSpec, dialogId, backstage) => ModalDialog.parts.footer(renderFooter(initSpec, dialogId, backstage));
  24820. const getCompByName = (access, name) => {
  24821. const root = access.getRoot();
  24822. if (root.getSystem().isConnected()) {
  24823. const form = Composing.getCurrent(access.getFormWrapper()).getOr(access.getFormWrapper());
  24824. return Form.getField(form, name).orThunk(() => {
  24825. const footer = access.getFooter();
  24826. const footerState = Reflecting.getState(footer).get();
  24827. return footerState.bind(f => f.lookupByName(name));
  24828. });
  24829. } else {
  24830. return Optional.none();
  24831. }
  24832. };
  24833. const validateData$1 = (access, data) => {
  24834. const root = access.getRoot();
  24835. return Reflecting.getState(root).get().map(dialogState => getOrDie(asRaw('data', dialogState.dataValidator, data))).getOr(data);
  24836. };
  24837. const getDialogApi = (access, doRedial, menuItemStates) => {
  24838. const withRoot = f => {
  24839. const root = access.getRoot();
  24840. if (root.getSystem().isConnected()) {
  24841. f(root);
  24842. }
  24843. };
  24844. const getData = () => {
  24845. const root = access.getRoot();
  24846. const valueComp = root.getSystem().isConnected() ? access.getFormWrapper() : root;
  24847. const representedValues = Representing.getValue(valueComp);
  24848. const menuItemCurrentState = map$1(menuItemStates, cell => cell.get());
  24849. return {
  24850. ...representedValues,
  24851. ...menuItemCurrentState
  24852. };
  24853. };
  24854. const setData = newData => {
  24855. withRoot(_ => {
  24856. const prevData = instanceApi.getData();
  24857. const mergedData = deepMerge(prevData, newData);
  24858. const newInternalData = validateData$1(access, mergedData);
  24859. const form = access.getFormWrapper();
  24860. Representing.setValue(form, newInternalData);
  24861. each(menuItemStates, (v, k) => {
  24862. if (has$2(mergedData, k)) {
  24863. v.set(mergedData[k]);
  24864. }
  24865. });
  24866. });
  24867. };
  24868. const setEnabled = (name, state) => {
  24869. getCompByName(access, name).each(state ? Disabling.enable : Disabling.disable);
  24870. };
  24871. const focus = name => {
  24872. getCompByName(access, name).each(Focusing.focus);
  24873. };
  24874. const block = message => {
  24875. if (!isString(message)) {
  24876. throw new Error('The dialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
  24877. }
  24878. withRoot(root => {
  24879. emitWith(root, formBlockEvent, { message });
  24880. });
  24881. };
  24882. const unblock = () => {
  24883. withRoot(root => {
  24884. emit(root, formUnblockEvent);
  24885. });
  24886. };
  24887. const showTab = name => {
  24888. withRoot(_ => {
  24889. const body = access.getBody();
  24890. const bodyState = Reflecting.getState(body);
  24891. if (bodyState.get().exists(b => b.isTabPanel())) {
  24892. Composing.getCurrent(body).each(tabSection => {
  24893. TabSection.showTab(tabSection, name);
  24894. });
  24895. }
  24896. });
  24897. };
  24898. const redial = d => {
  24899. withRoot(root => {
  24900. const id = access.getId();
  24901. const dialogInit = doRedial(d);
  24902. root.getSystem().broadcastOn([`${ dialogChannel }-${ id }`], dialogInit);
  24903. root.getSystem().broadcastOn([`${ titleChannel }-${ id }`], dialogInit.internalDialog);
  24904. root.getSystem().broadcastOn([`${ bodyChannel }-${ id }`], dialogInit.internalDialog);
  24905. root.getSystem().broadcastOn([`${ footerChannel }-${ id }`], dialogInit.internalDialog);
  24906. instanceApi.setData(dialogInit.initialData);
  24907. });
  24908. };
  24909. const close = () => {
  24910. withRoot(root => {
  24911. emit(root, formCloseEvent);
  24912. });
  24913. };
  24914. const instanceApi = {
  24915. getData,
  24916. setData,
  24917. setEnabled,
  24918. focus,
  24919. block,
  24920. unblock,
  24921. showTab,
  24922. redial,
  24923. close
  24924. };
  24925. return instanceApi;
  24926. };
  24927. const getDialogSizeClasses = size => {
  24928. switch (size) {
  24929. case 'large':
  24930. return ['tox-dialog--width-lg'];
  24931. case 'medium':
  24932. return ['tox-dialog--width-md'];
  24933. default:
  24934. return [];
  24935. }
  24936. };
  24937. const renderDialog = (dialogInit, extra, backstage) => {
  24938. const dialogId = generate$6('dialog');
  24939. const internalDialog = dialogInit.internalDialog;
  24940. const header = getHeader(internalDialog.title, dialogId, backstage);
  24941. const body = renderModalBody({
  24942. body: internalDialog.body,
  24943. initialData: internalDialog.initialData
  24944. }, dialogId, backstage);
  24945. const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
  24946. const objOfCells = extractCellsToObject(storagedMenuButtons);
  24947. const footer = renderModalFooter({ buttons: storagedMenuButtons }, dialogId, backstage);
  24948. const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra), backstage.shared.getSink);
  24949. const dialogSize = getDialogSizeClasses(internalDialog.size);
  24950. const spec = {
  24951. id: dialogId,
  24952. header,
  24953. body,
  24954. footer: Optional.some(footer),
  24955. extraClasses: dialogSize,
  24956. extraBehaviours: [],
  24957. extraStyles: {}
  24958. };
  24959. const dialog = renderModalDialog(spec, dialogInit, dialogEvents, backstage);
  24960. const modalAccess = (() => {
  24961. const getForm = () => {
  24962. const outerForm = ModalDialog.getBody(dialog);
  24963. return Composing.getCurrent(outerForm).getOr(outerForm);
  24964. };
  24965. return {
  24966. getId: constant$1(dialogId),
  24967. getRoot: constant$1(dialog),
  24968. getBody: () => ModalDialog.getBody(dialog),
  24969. getFooter: () => ModalDialog.getFooter(dialog),
  24970. getFormWrapper: getForm
  24971. };
  24972. })();
  24973. const instanceApi = getDialogApi(modalAccess, extra.redial, objOfCells);
  24974. return {
  24975. dialog,
  24976. instanceApi
  24977. };
  24978. };
  24979. const renderInlineDialog = (dialogInit, extra, backstage, ariaAttrs) => {
  24980. const dialogId = generate$6('dialog');
  24981. const dialogLabelId = generate$6('dialog-label');
  24982. const dialogContentId = generate$6('dialog-content');
  24983. const internalDialog = dialogInit.internalDialog;
  24984. const updateState = (_comp, incoming) => Optional.some(incoming);
  24985. const memHeader = record(renderInlineHeader({
  24986. title: internalDialog.title,
  24987. draggable: true
  24988. }, dialogId, dialogLabelId, backstage.shared.providers));
  24989. const memBody = record(renderInlineBody({
  24990. body: internalDialog.body,
  24991. initialData: internalDialog.initialData
  24992. }, dialogId, dialogContentId, backstage, ariaAttrs));
  24993. const storagedMenuButtons = mapMenuButtons(internalDialog.buttons);
  24994. const objOfCells = extractCellsToObject(storagedMenuButtons);
  24995. const memFooter = record(renderInlineFooter({ buttons: storagedMenuButtons }, dialogId, backstage));
  24996. const dialogEvents = SilverDialogEvents.initDialog(() => instanceApi, {
  24997. onBlock: event => {
  24998. Blocking.block(dialog, (_comp, bs) => getBusySpec(event.message, bs, backstage.shared.providers));
  24999. },
  25000. onUnblock: () => {
  25001. Blocking.unblock(dialog);
  25002. },
  25003. onClose: () => extra.closeWindow()
  25004. }, backstage.shared.getSink);
  25005. const dialog = build$1({
  25006. dom: {
  25007. tag: 'div',
  25008. classes: [
  25009. 'tox-dialog',
  25010. 'tox-dialog-inline'
  25011. ],
  25012. attributes: {
  25013. role: 'dialog',
  25014. ['aria-labelledby']: dialogLabelId,
  25015. ['aria-describedby']: dialogContentId
  25016. }
  25017. },
  25018. eventOrder: {
  25019. [receive()]: [
  25020. Reflecting.name(),
  25021. Receiving.name()
  25022. ],
  25023. [execute$5()]: ['execute-on-form'],
  25024. [attachedToDom()]: [
  25025. 'reflecting',
  25026. 'execute-on-form'
  25027. ]
  25028. },
  25029. behaviours: derive$1([
  25030. Keying.config({
  25031. mode: 'cyclic',
  25032. onEscape: c => {
  25033. emit(c, formCloseEvent);
  25034. return Optional.some(true);
  25035. },
  25036. useTabstopAt: elem => !isPseudoStop(elem) && (name$3(elem) !== 'button' || get$f(elem, 'disabled') !== 'disabled')
  25037. }),
  25038. Reflecting.config({
  25039. channel: `${ dialogChannel }-${ dialogId }`,
  25040. updateState,
  25041. initialData: dialogInit
  25042. }),
  25043. Focusing.config({}),
  25044. config('execute-on-form', dialogEvents.concat([runOnSource(focusin(), (comp, _se) => {
  25045. Keying.focusIn(comp);
  25046. })])),
  25047. Blocking.config({ getRoot: () => Optional.some(dialog) }),
  25048. Replacing.config({}),
  25049. RepresentingConfigs.memory({})
  25050. ]),
  25051. components: [
  25052. memHeader.asSpec(),
  25053. memBody.asSpec(),
  25054. memFooter.asSpec()
  25055. ]
  25056. });
  25057. const instanceApi = getDialogApi({
  25058. getId: constant$1(dialogId),
  25059. getRoot: constant$1(dialog),
  25060. getFooter: () => memFooter.get(dialog),
  25061. getBody: () => memBody.get(dialog),
  25062. getFormWrapper: () => {
  25063. const body = memBody.get(dialog);
  25064. return Composing.getCurrent(body).getOr(body);
  25065. }
  25066. }, extra.redial, objOfCells);
  25067. return {
  25068. dialog,
  25069. instanceApi
  25070. };
  25071. };
  25072. var global = tinymce.util.Tools.resolve('tinymce.util.URI');
  25073. const getUrlDialogApi = root => {
  25074. const withRoot = f => {
  25075. if (root.getSystem().isConnected()) {
  25076. f(root);
  25077. }
  25078. };
  25079. const block = message => {
  25080. if (!isString(message)) {
  25081. throw new Error('The urlDialogInstanceAPI.block function should be passed a blocking message of type string as an argument');
  25082. }
  25083. withRoot(root => {
  25084. emitWith(root, formBlockEvent, { message });
  25085. });
  25086. };
  25087. const unblock = () => {
  25088. withRoot(root => {
  25089. emit(root, formUnblockEvent);
  25090. });
  25091. };
  25092. const close = () => {
  25093. withRoot(root => {
  25094. emit(root, formCloseEvent);
  25095. });
  25096. };
  25097. const sendMessage = data => {
  25098. withRoot(root => {
  25099. root.getSystem().broadcastOn([bodySendMessageChannel], data);
  25100. });
  25101. };
  25102. return {
  25103. block,
  25104. unblock,
  25105. close,
  25106. sendMessage
  25107. };
  25108. };
  25109. const SUPPORTED_MESSAGE_ACTIONS = [
  25110. 'insertContent',
  25111. 'setContent',
  25112. 'execCommand',
  25113. 'close',
  25114. 'block',
  25115. 'unblock'
  25116. ];
  25117. const isSupportedMessage = data => isObject(data) && SUPPORTED_MESSAGE_ACTIONS.indexOf(data.mceAction) !== -1;
  25118. const isCustomMessage = data => !isSupportedMessage(data) && isObject(data) && has$2(data, 'mceAction');
  25119. const handleMessage = (editor, api, data) => {
  25120. switch (data.mceAction) {
  25121. case 'insertContent':
  25122. editor.insertContent(data.content);
  25123. break;
  25124. case 'setContent':
  25125. editor.setContent(data.content);
  25126. break;
  25127. case 'execCommand':
  25128. const ui = isBoolean(data.ui) ? data.ui : false;
  25129. editor.execCommand(data.cmd, ui, data.value);
  25130. break;
  25131. case 'close':
  25132. api.close();
  25133. break;
  25134. case 'block':
  25135. api.block(data.message);
  25136. break;
  25137. case 'unblock':
  25138. api.unblock();
  25139. break;
  25140. }
  25141. };
  25142. const renderUrlDialog = (internalDialog, extra, editor, backstage) => {
  25143. const dialogId = generate$6('dialog');
  25144. const header = getHeader(internalDialog.title, dialogId, backstage);
  25145. const body = renderIframeBody(internalDialog);
  25146. const footer = internalDialog.buttons.bind(buttons => {
  25147. if (buttons.length === 0) {
  25148. return Optional.none();
  25149. } else {
  25150. return Optional.some(renderModalFooter({ buttons }, dialogId, backstage));
  25151. }
  25152. });
  25153. const dialogEvents = SilverDialogEvents.initUrlDialog(() => instanceApi, getEventExtras(() => dialog, backstage.shared.providers, extra));
  25154. const styles = {
  25155. ...internalDialog.height.fold(() => ({}), height => ({
  25156. 'height': height + 'px',
  25157. 'max-height': height + 'px'
  25158. })),
  25159. ...internalDialog.width.fold(() => ({}), width => ({
  25160. 'width': width + 'px',
  25161. 'max-width': width + 'px'
  25162. }))
  25163. };
  25164. const classes = internalDialog.width.isNone() && internalDialog.height.isNone() ? ['tox-dialog--width-lg'] : [];
  25165. const iframeUri = new global(internalDialog.url, { base_uri: new global(window.location.href) });
  25166. const iframeDomain = `${ iframeUri.protocol }://${ iframeUri.host }${ iframeUri.port ? ':' + iframeUri.port : '' }`;
  25167. const messageHandlerUnbinder = unbindable();
  25168. const extraBehaviours = [
  25169. config('messages', [
  25170. runOnAttached(() => {
  25171. const unbind = bind(SugarElement.fromDom(window), 'message', e => {
  25172. if (iframeUri.isSameOrigin(new global(e.raw.origin))) {
  25173. const data = e.raw.data;
  25174. if (isSupportedMessage(data)) {
  25175. handleMessage(editor, instanceApi, data);
  25176. } else if (isCustomMessage(data)) {
  25177. internalDialog.onMessage(instanceApi, data);
  25178. }
  25179. }
  25180. });
  25181. messageHandlerUnbinder.set(unbind);
  25182. }),
  25183. runOnDetached(messageHandlerUnbinder.clear)
  25184. ]),
  25185. Receiving.config({
  25186. channels: {
  25187. [bodySendMessageChannel]: {
  25188. onReceive: (comp, data) => {
  25189. descendant(comp.element, 'iframe').each(iframeEle => {
  25190. const iframeWin = iframeEle.dom.contentWindow;
  25191. iframeWin.postMessage(data, iframeDomain);
  25192. });
  25193. }
  25194. }
  25195. }
  25196. })
  25197. ];
  25198. const spec = {
  25199. id: dialogId,
  25200. header,
  25201. body,
  25202. footer,
  25203. extraClasses: classes,
  25204. extraBehaviours,
  25205. extraStyles: styles
  25206. };
  25207. const dialog = renderModalDialog(spec, internalDialog, dialogEvents, backstage);
  25208. const instanceApi = getUrlDialogApi(dialog);
  25209. return {
  25210. dialog,
  25211. instanceApi
  25212. };
  25213. };
  25214. const setup$2 = extras => {
  25215. const sharedBackstage = extras.backstage.shared;
  25216. const open = (message, callback) => {
  25217. const closeDialog = () => {
  25218. ModalDialog.hide(alertDialog);
  25219. callback();
  25220. };
  25221. const memFooterClose = record(renderFooterButton({
  25222. name: 'close-alert',
  25223. text: 'OK',
  25224. primary: true,
  25225. buttonType: Optional.some('primary'),
  25226. align: 'end',
  25227. enabled: true,
  25228. icon: Optional.none()
  25229. }, 'cancel', extras.backstage));
  25230. const titleSpec = pUntitled();
  25231. const closeSpec = pClose(closeDialog, sharedBackstage.providers);
  25232. const alertDialog = build$1(renderDialog$1({
  25233. lazySink: () => sharedBackstage.getSink(),
  25234. header: hiddenHeader(titleSpec, closeSpec),
  25235. body: pBodyMessage(message, sharedBackstage.providers),
  25236. footer: Optional.some(pFooter(pFooterGroup([], [memFooterClose.asSpec()]))),
  25237. onEscape: closeDialog,
  25238. extraClasses: ['tox-alert-dialog'],
  25239. extraBehaviours: [],
  25240. extraStyles: {},
  25241. dialogEvents: [run$1(formCancelEvent, closeDialog)],
  25242. eventOrder: {}
  25243. }));
  25244. ModalDialog.show(alertDialog);
  25245. const footerCloseButton = memFooterClose.get(alertDialog);
  25246. Focusing.focus(footerCloseButton);
  25247. };
  25248. return { open };
  25249. };
  25250. const setup$1 = extras => {
  25251. const sharedBackstage = extras.backstage.shared;
  25252. const open = (message, callback) => {
  25253. const closeDialog = state => {
  25254. ModalDialog.hide(confirmDialog);
  25255. callback(state);
  25256. };
  25257. const memFooterYes = record(renderFooterButton({
  25258. name: 'yes',
  25259. text: 'Yes',
  25260. primary: true,
  25261. buttonType: Optional.some('primary'),
  25262. align: 'end',
  25263. enabled: true,
  25264. icon: Optional.none()
  25265. }, 'submit', extras.backstage));
  25266. const footerNo = renderFooterButton({
  25267. name: 'no',
  25268. text: 'No',
  25269. primary: false,
  25270. buttonType: Optional.some('secondary'),
  25271. align: 'end',
  25272. enabled: true,
  25273. icon: Optional.none()
  25274. }, 'cancel', extras.backstage);
  25275. const titleSpec = pUntitled();
  25276. const closeSpec = pClose(() => closeDialog(false), sharedBackstage.providers);
  25277. const confirmDialog = build$1(renderDialog$1({
  25278. lazySink: () => sharedBackstage.getSink(),
  25279. header: hiddenHeader(titleSpec, closeSpec),
  25280. body: pBodyMessage(message, sharedBackstage.providers),
  25281. footer: Optional.some(pFooter(pFooterGroup([], [
  25282. footerNo,
  25283. memFooterYes.asSpec()
  25284. ]))),
  25285. onEscape: () => closeDialog(false),
  25286. extraClasses: ['tox-confirm-dialog'],
  25287. extraBehaviours: [],
  25288. extraStyles: {},
  25289. dialogEvents: [
  25290. run$1(formCancelEvent, () => closeDialog(false)),
  25291. run$1(formSubmitEvent, () => closeDialog(true))
  25292. ],
  25293. eventOrder: {}
  25294. }));
  25295. ModalDialog.show(confirmDialog);
  25296. const footerYesButton = memFooterYes.get(confirmDialog);
  25297. Focusing.focus(footerYesButton);
  25298. };
  25299. return { open };
  25300. };
  25301. const validateData = (data, validator) => getOrDie(asRaw('data', validator, data));
  25302. const isAlertOrConfirmDialog = target => closest(target, '.tox-alert-dialog') || closest(target, '.tox-confirm-dialog');
  25303. const inlineAdditionalBehaviours = (editor, isStickyToolbar, isToolbarLocationTop) => {
  25304. if (isStickyToolbar && isToolbarLocationTop) {
  25305. return [];
  25306. } else {
  25307. return [Docking.config({
  25308. contextual: {
  25309. lazyContext: () => Optional.some(box$1(SugarElement.fromDom(editor.getContentAreaContainer()))),
  25310. fadeInClass: 'tox-dialog-dock-fadein',
  25311. fadeOutClass: 'tox-dialog-dock-fadeout',
  25312. transitionClass: 'tox-dialog-dock-transition'
  25313. },
  25314. modes: ['top']
  25315. })];
  25316. }
  25317. };
  25318. const setup = extras => {
  25319. const backstage = extras.backstage;
  25320. const editor = extras.editor;
  25321. const isStickyToolbar$1 = isStickyToolbar(editor);
  25322. const alertDialog = setup$2(extras);
  25323. const confirmDialog = setup$1(extras);
  25324. const open = (config, params, closeWindow) => {
  25325. if (params !== undefined && params.inline === 'toolbar') {
  25326. return openInlineDialog(config, backstage.shared.anchors.inlineDialog(), closeWindow, params.ariaAttrs);
  25327. } else if (params !== undefined && params.inline === 'cursor') {
  25328. return openInlineDialog(config, backstage.shared.anchors.cursor(), closeWindow, params.ariaAttrs);
  25329. } else {
  25330. return openModalDialog(config, closeWindow);
  25331. }
  25332. };
  25333. const openUrl = (config, closeWindow) => openModalUrlDialog(config, closeWindow);
  25334. const openModalUrlDialog = (config, closeWindow) => {
  25335. const factory = contents => {
  25336. const dialog = renderUrlDialog(contents, {
  25337. closeWindow: () => {
  25338. ModalDialog.hide(dialog.dialog);
  25339. closeWindow(dialog.instanceApi);
  25340. }
  25341. }, editor, backstage);
  25342. ModalDialog.show(dialog.dialog);
  25343. return dialog.instanceApi;
  25344. };
  25345. return DialogManager.openUrl(factory, config);
  25346. };
  25347. const openModalDialog = (config, closeWindow) => {
  25348. const factory = (contents, internalInitialData, dataValidator) => {
  25349. const initialData = internalInitialData;
  25350. const dialogInit = {
  25351. dataValidator,
  25352. initialData,
  25353. internalDialog: contents
  25354. };
  25355. const dialog = renderDialog(dialogInit, {
  25356. redial: DialogManager.redial,
  25357. closeWindow: () => {
  25358. ModalDialog.hide(dialog.dialog);
  25359. closeWindow(dialog.instanceApi);
  25360. }
  25361. }, backstage);
  25362. ModalDialog.show(dialog.dialog);
  25363. dialog.instanceApi.setData(initialData);
  25364. return dialog.instanceApi;
  25365. };
  25366. return DialogManager.open(factory, config);
  25367. };
  25368. const openInlineDialog = (config$1, anchor, closeWindow, ariaAttrs) => {
  25369. const factory = (contents, internalInitialData, dataValidator) => {
  25370. const initialData = validateData(internalInitialData, dataValidator);
  25371. const inlineDialog = value$2();
  25372. const isToolbarLocationTop = backstage.shared.header.isPositionedAtTop();
  25373. const dialogInit = {
  25374. dataValidator,
  25375. initialData,
  25376. internalDialog: contents
  25377. };
  25378. const refreshDocking = () => inlineDialog.on(dialog => {
  25379. InlineView.reposition(dialog);
  25380. Docking.refresh(dialog);
  25381. });
  25382. const dialogUi = renderInlineDialog(dialogInit, {
  25383. redial: DialogManager.redial,
  25384. closeWindow: () => {
  25385. inlineDialog.on(InlineView.hide);
  25386. editor.off('ResizeEditor', refreshDocking);
  25387. inlineDialog.clear();
  25388. closeWindow(dialogUi.instanceApi);
  25389. }
  25390. }, backstage, ariaAttrs);
  25391. const inlineDialogComp = build$1(InlineView.sketch({
  25392. lazySink: backstage.shared.getSink,
  25393. dom: {
  25394. tag: 'div',
  25395. classes: []
  25396. },
  25397. fireDismissalEventInstead: {},
  25398. ...isToolbarLocationTop ? {} : { fireRepositionEventInstead: {} },
  25399. inlineBehaviours: derive$1([
  25400. config('window-manager-inline-events', [run$1(dismissRequested(), (_comp, _se) => {
  25401. emit(dialogUi.dialog, formCancelEvent);
  25402. })]),
  25403. ...inlineAdditionalBehaviours(editor, isStickyToolbar$1, isToolbarLocationTop)
  25404. ]),
  25405. isExtraPart: (_comp, target) => isAlertOrConfirmDialog(target)
  25406. }));
  25407. inlineDialog.set(inlineDialogComp);
  25408. InlineView.showWithin(inlineDialogComp, premade(dialogUi.dialog), { anchor }, Optional.some(body()));
  25409. if (!isStickyToolbar$1 || !isToolbarLocationTop) {
  25410. Docking.refresh(inlineDialogComp);
  25411. editor.on('ResizeEditor', refreshDocking);
  25412. }
  25413. dialogUi.instanceApi.setData(initialData);
  25414. Keying.focusIn(dialogUi.dialog);
  25415. return dialogUi.instanceApi;
  25416. };
  25417. return DialogManager.open(factory, config$1);
  25418. };
  25419. const confirm = (message, callback) => {
  25420. confirmDialog.open(message, state => {
  25421. callback(state);
  25422. });
  25423. };
  25424. const alert = (message, callback) => {
  25425. alertDialog.open(message, () => {
  25426. callback();
  25427. });
  25428. };
  25429. const close = instanceApi => {
  25430. instanceApi.close();
  25431. };
  25432. return {
  25433. open,
  25434. openUrl,
  25435. alert,
  25436. close,
  25437. confirm
  25438. };
  25439. };
  25440. const registerOptions = editor => {
  25441. register$e(editor);
  25442. register$d(editor);
  25443. register(editor);
  25444. };
  25445. var Theme = () => {
  25446. global$a.add('silver', editor => {
  25447. registerOptions(editor);
  25448. const {getUiMothership, backstage, renderUI} = setup$3(editor);
  25449. Autocompleter.register(editor, backstage.shared);
  25450. const windowMgr = setup({
  25451. editor,
  25452. backstage
  25453. });
  25454. return {
  25455. renderUI,
  25456. getWindowManagerImpl: constant$1(windowMgr),
  25457. getNotificationManagerImpl: () => NotificationManagerImpl(editor, { backstage }, getUiMothership())
  25458. };
  25459. });
  25460. };
  25461. Theme();
  25462. })();