tinymce.js 1.1 MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842298432984429845298462984729848298492985029851298522985329854298552985629857298582985929860298612986229863298642986529866298672986829869298702987129872298732987429875298762987729878298792988029881298822988329884298852988629887298882988929890298912989229893298942989529896298972989829899299002990129902299032990429905299062990729908299092991029911299122991329914299152991629917299182991929920299212992229923299242992529926299272992829929299302993129932299332993429935299362993729938299392994029941299422994329944299452994629947299482994929950299512995229953299542995529956299572995829959299602996129962299632996429965299662996729968299692997029971299722997329974299752997629977299782997929980299812998229983299842998529986299872998829989299902999129992299932999429995299962999729998299993000030001300023000330004300053000630007300083000930010300113001230013300143001530016300173001830019300203002130022300233002430025300263002730028300293003030031300323003330034300353003630037300383003930040300413004230043300443004530046300473004830049300503005130052300533005430055300563005730058300593006030061300623006330064300653006630067300683006930070300713007230073300743007530076300773007830079300803008130082300833008430085300863008730088300893009030091300923009330094300953009630097300983009930100301013010230103301043010530106301073010830109301103011130112301133011430115301163011730118301193012030121301223012330124301253012630127301283012930130301313013230133301343013530136301373013830139301403014130142301433014430145301463014730148301493015030151301523015330154301553015630157301583015930160301613016230163301643016530166301673016830169301703017130172301733017430175301763017730178301793018030181301823018330184301853018630187301883018930190301913019230193301943019530196301973019830199302003020130202302033020430205302063020730208302093021030211302123021330214302153021630217302183021930220302213022230223302243022530226302273022830229302303023130232302333023430235302363023730238
  1. /**
  2. * TinyMCE version 6.3.1 (2022-12-06)
  3. */
  4. (function () {
  5. 'use strict';
  6. var typeOf$1 = function (x) {
  7. if (x === null) {
  8. return 'null';
  9. }
  10. if (x === undefined) {
  11. return 'undefined';
  12. }
  13. var t = typeof x;
  14. if (t === 'object' && (Array.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'Array')) {
  15. return 'array';
  16. }
  17. if (t === 'object' && (String.prototype.isPrototypeOf(x) || x.constructor && x.constructor.name === 'String')) {
  18. return 'string';
  19. }
  20. return t;
  21. };
  22. var isEquatableType = function (x) {
  23. return [
  24. 'undefined',
  25. 'boolean',
  26. 'number',
  27. 'string',
  28. 'function',
  29. 'xml',
  30. 'null'
  31. ].indexOf(x) !== -1;
  32. };
  33. var sort$1 = function (xs, compareFn) {
  34. var clone = Array.prototype.slice.call(xs);
  35. return clone.sort(compareFn);
  36. };
  37. var contramap = function (eqa, f) {
  38. return eq$2(function (x, y) {
  39. return eqa.eq(f(x), f(y));
  40. });
  41. };
  42. var eq$2 = function (f) {
  43. return { eq: f };
  44. };
  45. var tripleEq = eq$2(function (x, y) {
  46. return x === y;
  47. });
  48. var eqString = tripleEq;
  49. var eqArray = function (eqa) {
  50. return eq$2(function (x, y) {
  51. if (x.length !== y.length) {
  52. return false;
  53. }
  54. var len = x.length;
  55. for (var i = 0; i < len; i++) {
  56. if (!eqa.eq(x[i], y[i])) {
  57. return false;
  58. }
  59. }
  60. return true;
  61. });
  62. };
  63. var eqSortedArray = function (eqa, compareFn) {
  64. return contramap(eqArray(eqa), function (xs) {
  65. return sort$1(xs, compareFn);
  66. });
  67. };
  68. var eqRecord = function (eqa) {
  69. return eq$2(function (x, y) {
  70. var kx = Object.keys(x);
  71. var ky = Object.keys(y);
  72. if (!eqSortedArray(eqString).eq(kx, ky)) {
  73. return false;
  74. }
  75. var len = kx.length;
  76. for (var i = 0; i < len; i++) {
  77. var q = kx[i];
  78. if (!eqa.eq(x[q], y[q])) {
  79. return false;
  80. }
  81. }
  82. return true;
  83. });
  84. };
  85. var eqAny = eq$2(function (x, y) {
  86. if (x === y) {
  87. return true;
  88. }
  89. var tx = typeOf$1(x);
  90. var ty = typeOf$1(y);
  91. if (tx !== ty) {
  92. return false;
  93. }
  94. if (isEquatableType(tx)) {
  95. return x === y;
  96. } else if (tx === 'array') {
  97. return eqArray(eqAny).eq(x, y);
  98. } else if (tx === 'object') {
  99. return eqRecord(eqAny).eq(x, y);
  100. }
  101. return false;
  102. });
  103. const getPrototypeOf$1 = Object.getPrototypeOf;
  104. const hasProto = (v, constructor, predicate) => {
  105. var _a;
  106. if (predicate(v, constructor.prototype)) {
  107. return true;
  108. } else {
  109. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  110. }
  111. };
  112. const typeOf = x => {
  113. const t = typeof x;
  114. if (x === null) {
  115. return 'null';
  116. } else if (t === 'object' && Array.isArray(x)) {
  117. return 'array';
  118. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  119. return 'string';
  120. } else {
  121. return t;
  122. }
  123. };
  124. const isType$1 = type => value => typeOf(value) === type;
  125. const isSimpleType = type => value => typeof value === type;
  126. const eq$1 = t => a => t === a;
  127. const is$4 = (value, constructor) => isObject(value) && hasProto(value, constructor, (o, proto) => getPrototypeOf$1(o) === proto);
  128. const isString = isType$1('string');
  129. const isObject = isType$1('object');
  130. const isPlainObject = value => is$4(value, Object);
  131. const isArray$1 = isType$1('array');
  132. const isNull = eq$1(null);
  133. const isBoolean = isSimpleType('boolean');
  134. const isUndefined = eq$1(undefined);
  135. const isNullable = a => a === null || a === undefined;
  136. const isNonNullable = a => !isNullable(a);
  137. const isFunction = isSimpleType('function');
  138. const isNumber = isSimpleType('number');
  139. const isArrayOf = (value, pred) => {
  140. if (isArray$1(value)) {
  141. for (let i = 0, len = value.length; i < len; ++i) {
  142. if (!pred(value[i])) {
  143. return false;
  144. }
  145. }
  146. return true;
  147. }
  148. return false;
  149. };
  150. const noop = () => {
  151. };
  152. const compose = (fa, fb) => {
  153. return (...args) => {
  154. return fa(fb.apply(null, args));
  155. };
  156. };
  157. const compose1 = (fbc, fab) => a => fbc(fab(a));
  158. const constant = value => {
  159. return () => {
  160. return value;
  161. };
  162. };
  163. const identity = x => {
  164. return x;
  165. };
  166. const tripleEquals = (a, b) => {
  167. return a === b;
  168. };
  169. function curry(fn, ...initialArgs) {
  170. return (...restArgs) => {
  171. const all = initialArgs.concat(restArgs);
  172. return fn.apply(null, all);
  173. };
  174. }
  175. const not = f => t => !f(t);
  176. const die = msg => {
  177. return () => {
  178. throw new Error(msg);
  179. };
  180. };
  181. const apply$1 = f => {
  182. return f();
  183. };
  184. const call = f => {
  185. f();
  186. };
  187. const never = constant(false);
  188. const always = constant(true);
  189. class Optional {
  190. constructor(tag, value) {
  191. this.tag = tag;
  192. this.value = value;
  193. }
  194. static some(value) {
  195. return new Optional(true, value);
  196. }
  197. static none() {
  198. return Optional.singletonNone;
  199. }
  200. fold(onNone, onSome) {
  201. if (this.tag) {
  202. return onSome(this.value);
  203. } else {
  204. return onNone();
  205. }
  206. }
  207. isSome() {
  208. return this.tag;
  209. }
  210. isNone() {
  211. return !this.tag;
  212. }
  213. map(mapper) {
  214. if (this.tag) {
  215. return Optional.some(mapper(this.value));
  216. } else {
  217. return Optional.none();
  218. }
  219. }
  220. bind(binder) {
  221. if (this.tag) {
  222. return binder(this.value);
  223. } else {
  224. return Optional.none();
  225. }
  226. }
  227. exists(predicate) {
  228. return this.tag && predicate(this.value);
  229. }
  230. forall(predicate) {
  231. return !this.tag || predicate(this.value);
  232. }
  233. filter(predicate) {
  234. if (!this.tag || predicate(this.value)) {
  235. return this;
  236. } else {
  237. return Optional.none();
  238. }
  239. }
  240. getOr(replacement) {
  241. return this.tag ? this.value : replacement;
  242. }
  243. or(replacement) {
  244. return this.tag ? this : replacement;
  245. }
  246. getOrThunk(thunk) {
  247. return this.tag ? this.value : thunk();
  248. }
  249. orThunk(thunk) {
  250. return this.tag ? this : thunk();
  251. }
  252. getOrDie(message) {
  253. if (!this.tag) {
  254. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  255. } else {
  256. return this.value;
  257. }
  258. }
  259. static from(value) {
  260. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  261. }
  262. getOrNull() {
  263. return this.tag ? this.value : null;
  264. }
  265. getOrUndefined() {
  266. return this.value;
  267. }
  268. each(worker) {
  269. if (this.tag) {
  270. worker(this.value);
  271. }
  272. }
  273. toArray() {
  274. return this.tag ? [this.value] : [];
  275. }
  276. toString() {
  277. return this.tag ? `some(${ this.value })` : 'none()';
  278. }
  279. }
  280. Optional.singletonNone = new Optional(false);
  281. const nativeSlice = Array.prototype.slice;
  282. const nativeIndexOf = Array.prototype.indexOf;
  283. const nativePush = Array.prototype.push;
  284. const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  285. const indexOf$1 = (xs, x) => {
  286. const r = rawIndexOf(xs, x);
  287. return r === -1 ? Optional.none() : Optional.some(r);
  288. };
  289. const contains$2 = (xs, x) => rawIndexOf(xs, x) > -1;
  290. const exists = (xs, pred) => {
  291. for (let i = 0, len = xs.length; i < len; i++) {
  292. const x = xs[i];
  293. if (pred(x, i)) {
  294. return true;
  295. }
  296. }
  297. return false;
  298. };
  299. const map$3 = (xs, f) => {
  300. const len = xs.length;
  301. const r = new Array(len);
  302. for (let i = 0; i < len; i++) {
  303. const x = xs[i];
  304. r[i] = f(x, i);
  305. }
  306. return r;
  307. };
  308. const each$e = (xs, f) => {
  309. for (let i = 0, len = xs.length; i < len; i++) {
  310. const x = xs[i];
  311. f(x, i);
  312. }
  313. };
  314. const eachr = (xs, f) => {
  315. for (let i = xs.length - 1; i >= 0; i--) {
  316. const x = xs[i];
  317. f(x, i);
  318. }
  319. };
  320. const partition$2 = (xs, pred) => {
  321. const pass = [];
  322. const fail = [];
  323. for (let i = 0, len = xs.length; i < len; i++) {
  324. const x = xs[i];
  325. const arr = pred(x, i) ? pass : fail;
  326. arr.push(x);
  327. }
  328. return {
  329. pass,
  330. fail
  331. };
  332. };
  333. const filter$5 = (xs, pred) => {
  334. const r = [];
  335. for (let i = 0, len = xs.length; i < len; i++) {
  336. const x = xs[i];
  337. if (pred(x, i)) {
  338. r.push(x);
  339. }
  340. }
  341. return r;
  342. };
  343. const foldr = (xs, f, acc) => {
  344. eachr(xs, (x, i) => {
  345. acc = f(acc, x, i);
  346. });
  347. return acc;
  348. };
  349. const foldl = (xs, f, acc) => {
  350. each$e(xs, (x, i) => {
  351. acc = f(acc, x, i);
  352. });
  353. return acc;
  354. };
  355. const findUntil$1 = (xs, pred, until) => {
  356. for (let i = 0, len = xs.length; i < len; i++) {
  357. const x = xs[i];
  358. if (pred(x, i)) {
  359. return Optional.some(x);
  360. } else if (until(x, i)) {
  361. break;
  362. }
  363. }
  364. return Optional.none();
  365. };
  366. const find$2 = (xs, pred) => {
  367. return findUntil$1(xs, pred, never);
  368. };
  369. const findIndex$2 = (xs, pred) => {
  370. for (let i = 0, len = xs.length; i < len; i++) {
  371. const x = xs[i];
  372. if (pred(x, i)) {
  373. return Optional.some(i);
  374. }
  375. }
  376. return Optional.none();
  377. };
  378. const flatten = xs => {
  379. const r = [];
  380. for (let i = 0, len = xs.length; i < len; ++i) {
  381. if (!isArray$1(xs[i])) {
  382. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  383. }
  384. nativePush.apply(r, xs[i]);
  385. }
  386. return r;
  387. };
  388. const bind$3 = (xs, f) => flatten(map$3(xs, f));
  389. const forall = (xs, pred) => {
  390. for (let i = 0, len = xs.length; i < len; ++i) {
  391. const x = xs[i];
  392. if (pred(x, i) !== true) {
  393. return false;
  394. }
  395. }
  396. return true;
  397. };
  398. const reverse = xs => {
  399. const r = nativeSlice.call(xs, 0);
  400. r.reverse();
  401. return r;
  402. };
  403. const difference = (a1, a2) => filter$5(a1, x => !contains$2(a2, x));
  404. const mapToObject = (xs, f) => {
  405. const r = {};
  406. for (let i = 0, len = xs.length; i < len; i++) {
  407. const x = xs[i];
  408. r[String(x)] = f(x, i);
  409. }
  410. return r;
  411. };
  412. const sort = (xs, comparator) => {
  413. const copy = nativeSlice.call(xs, 0);
  414. copy.sort(comparator);
  415. return copy;
  416. };
  417. const get$b = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  418. const head = xs => get$b(xs, 0);
  419. const last$3 = xs => get$b(xs, xs.length - 1);
  420. const from = isFunction(Array.from) ? Array.from : x => nativeSlice.call(x);
  421. const findMap = (arr, f) => {
  422. for (let i = 0; i < arr.length; i++) {
  423. const r = f(arr[i], i);
  424. if (r.isSome()) {
  425. return r;
  426. }
  427. }
  428. return Optional.none();
  429. };
  430. const unique$1 = (xs, comparator) => {
  431. const r = [];
  432. const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$2(r, x);
  433. for (let i = 0, len = xs.length; i < len; i++) {
  434. const x = xs[i];
  435. if (!isDuplicated(x)) {
  436. r.push(x);
  437. }
  438. }
  439. return r;
  440. };
  441. const keys = Object.keys;
  442. const hasOwnProperty$2 = Object.hasOwnProperty;
  443. const each$d = (obj, f) => {
  444. const props = keys(obj);
  445. for (let k = 0, len = props.length; k < len; k++) {
  446. const i = props[k];
  447. const x = obj[i];
  448. f(x, i);
  449. }
  450. };
  451. const map$2 = (obj, f) => {
  452. return tupleMap(obj, (x, i) => ({
  453. k: i,
  454. v: f(x, i)
  455. }));
  456. };
  457. const tupleMap = (obj, f) => {
  458. const r = {};
  459. each$d(obj, (x, i) => {
  460. const tuple = f(x, i);
  461. r[tuple.k] = tuple.v;
  462. });
  463. return r;
  464. };
  465. const objAcc = r => (x, i) => {
  466. r[i] = x;
  467. };
  468. const internalFilter = (obj, pred, onTrue, onFalse) => {
  469. each$d(obj, (x, i) => {
  470. (pred(x, i) ? onTrue : onFalse)(x, i);
  471. });
  472. };
  473. const bifilter = (obj, pred) => {
  474. const t = {};
  475. const f = {};
  476. internalFilter(obj, pred, objAcc(t), objAcc(f));
  477. return {
  478. t,
  479. f
  480. };
  481. };
  482. const filter$4 = (obj, pred) => {
  483. const t = {};
  484. internalFilter(obj, pred, objAcc(t), noop);
  485. return t;
  486. };
  487. const mapToArray = (obj, f) => {
  488. const r = [];
  489. each$d(obj, (value, name) => {
  490. r.push(f(value, name));
  491. });
  492. return r;
  493. };
  494. const values = obj => {
  495. return mapToArray(obj, identity);
  496. };
  497. const get$a = (obj, key) => {
  498. return has$2(obj, key) ? Optional.from(obj[key]) : Optional.none();
  499. };
  500. const has$2 = (obj, key) => hasOwnProperty$2.call(obj, key);
  501. const hasNonNullableKey = (obj, key) => has$2(obj, key) && obj[key] !== undefined && obj[key] !== null;
  502. const equal$1 = (a1, a2, eq = eqAny) => eqRecord(eq).eq(a1, a2);
  503. const stringArray = a => {
  504. const all = {};
  505. each$e(a, key => {
  506. all[key] = {};
  507. });
  508. return keys(all);
  509. };
  510. const isArrayLike = o => o.length !== undefined;
  511. const isArray = Array.isArray;
  512. const toArray$1 = obj => {
  513. if (!isArray(obj)) {
  514. const array = [];
  515. for (let i = 0, l = obj.length; i < l; i++) {
  516. array[i] = obj[i];
  517. }
  518. return array;
  519. } else {
  520. return obj;
  521. }
  522. };
  523. const each$c = (o, cb, s) => {
  524. if (!o) {
  525. return false;
  526. }
  527. s = s || o;
  528. if (isArrayLike(o)) {
  529. for (let n = 0, l = o.length; n < l; n++) {
  530. if (cb.call(s, o[n], n, o) === false) {
  531. return false;
  532. }
  533. }
  534. } else {
  535. for (const n in o) {
  536. if (has$2(o, n)) {
  537. if (cb.call(s, o[n], n, o) === false) {
  538. return false;
  539. }
  540. }
  541. }
  542. }
  543. return true;
  544. };
  545. const map$1 = (array, callback) => {
  546. const out = [];
  547. each$c(array, (item, index) => {
  548. out.push(callback(item, index, array));
  549. });
  550. return out;
  551. };
  552. const filter$3 = (a, f) => {
  553. const o = [];
  554. each$c(a, (v, index) => {
  555. if (!f || f(v, index, a)) {
  556. o.push(v);
  557. }
  558. });
  559. return o;
  560. };
  561. const indexOf = (a, v) => {
  562. if (a) {
  563. for (let i = 0, l = a.length; i < l; i++) {
  564. if (a[i] === v) {
  565. return i;
  566. }
  567. }
  568. }
  569. return -1;
  570. };
  571. const reduce = (collection, iteratee, accumulator, thisArg) => {
  572. let acc = isUndefined(accumulator) ? collection[0] : accumulator;
  573. for (let i = 0; i < collection.length; i++) {
  574. acc = iteratee.call(thisArg, acc, collection[i], i);
  575. }
  576. return acc;
  577. };
  578. const findIndex$1 = (array, predicate, thisArg) => {
  579. for (let i = 0, l = array.length; i < l; i++) {
  580. if (predicate.call(thisArg, array[i], i, array)) {
  581. return i;
  582. }
  583. }
  584. return -1;
  585. };
  586. const last$2 = collection => collection[collection.length - 1];
  587. const cached = f => {
  588. let called = false;
  589. let r;
  590. return (...args) => {
  591. if (!called) {
  592. called = true;
  593. r = f.apply(null, args);
  594. }
  595. return r;
  596. };
  597. };
  598. const DeviceType = (os, browser, userAgent, mediaMatch) => {
  599. const isiPad = os.isiOS() && /ipad/i.test(userAgent) === true;
  600. const isiPhone = os.isiOS() && !isiPad;
  601. const isMobile = os.isiOS() || os.isAndroid();
  602. const isTouch = isMobile || mediaMatch('(pointer:coarse)');
  603. const isTablet = isiPad || !isiPhone && isMobile && mediaMatch('(min-device-width:768px)');
  604. const isPhone = isiPhone || isMobile && !isTablet;
  605. const iOSwebview = browser.isSafari() && os.isiOS() && /safari/i.test(userAgent) === false;
  606. const isDesktop = !isPhone && !isTablet && !iOSwebview;
  607. return {
  608. isiPad: constant(isiPad),
  609. isiPhone: constant(isiPhone),
  610. isTablet: constant(isTablet),
  611. isPhone: constant(isPhone),
  612. isTouch: constant(isTouch),
  613. isAndroid: os.isAndroid,
  614. isiOS: os.isiOS,
  615. isWebView: constant(iOSwebview),
  616. isDesktop: constant(isDesktop)
  617. };
  618. };
  619. const firstMatch = (regexes, s) => {
  620. for (let i = 0; i < regexes.length; i++) {
  621. const x = regexes[i];
  622. if (x.test(s)) {
  623. return x;
  624. }
  625. }
  626. return undefined;
  627. };
  628. const find$1 = (regexes, agent) => {
  629. const r = firstMatch(regexes, agent);
  630. if (!r) {
  631. return {
  632. major: 0,
  633. minor: 0
  634. };
  635. }
  636. const group = i => {
  637. return Number(agent.replace(r, '$' + i));
  638. };
  639. return nu$3(group(1), group(2));
  640. };
  641. const detect$5 = (versionRegexes, agent) => {
  642. const cleanedAgent = String(agent).toLowerCase();
  643. if (versionRegexes.length === 0) {
  644. return unknown$2();
  645. }
  646. return find$1(versionRegexes, cleanedAgent);
  647. };
  648. const unknown$2 = () => {
  649. return nu$3(0, 0);
  650. };
  651. const nu$3 = (major, minor) => {
  652. return {
  653. major,
  654. minor
  655. };
  656. };
  657. const Version = {
  658. nu: nu$3,
  659. detect: detect$5,
  660. unknown: unknown$2
  661. };
  662. const detectBrowser$1 = (browsers, userAgentData) => {
  663. return findMap(userAgentData.brands, uaBrand => {
  664. const lcBrand = uaBrand.brand.toLowerCase();
  665. return find$2(browsers, browser => {
  666. var _a;
  667. return lcBrand === ((_a = browser.brand) === null || _a === void 0 ? void 0 : _a.toLowerCase());
  668. }).map(info => ({
  669. current: info.name,
  670. version: Version.nu(parseInt(uaBrand.version, 10), 0)
  671. }));
  672. });
  673. };
  674. const detect$4 = (candidates, userAgent) => {
  675. const agent = String(userAgent).toLowerCase();
  676. return find$2(candidates, candidate => {
  677. return candidate.search(agent);
  678. });
  679. };
  680. const detectBrowser = (browsers, userAgent) => {
  681. return detect$4(browsers, userAgent).map(browser => {
  682. const version = Version.detect(browser.versionRegexes, userAgent);
  683. return {
  684. current: browser.name,
  685. version
  686. };
  687. });
  688. };
  689. const detectOs = (oses, userAgent) => {
  690. return detect$4(oses, userAgent).map(os => {
  691. const version = Version.detect(os.versionRegexes, userAgent);
  692. return {
  693. current: os.name,
  694. version
  695. };
  696. });
  697. };
  698. const removeFromStart = (str, numChars) => {
  699. return str.substring(numChars);
  700. };
  701. const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  702. const removeLeading = (str, prefix) => {
  703. return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  704. };
  705. const contains$1 = (str, substr, start = 0, end) => {
  706. const idx = str.indexOf(substr, start);
  707. if (idx !== -1) {
  708. return isUndefined(end) ? true : idx + substr.length <= end;
  709. } else {
  710. return false;
  711. }
  712. };
  713. const startsWith = (str, prefix) => {
  714. return checkRange(str, prefix, 0);
  715. };
  716. const endsWith = (str, suffix) => {
  717. return checkRange(str, suffix, str.length - suffix.length);
  718. };
  719. const blank = r => s => s.replace(r, '');
  720. const trim$3 = blank(/^\s+|\s+$/g);
  721. const lTrim = blank(/^\s+/g);
  722. const rTrim = blank(/\s+$/g);
  723. const isNotEmpty = s => s.length > 0;
  724. const isEmpty$3 = s => !isNotEmpty(s);
  725. const repeat = (s, count) => count <= 0 ? '' : new Array(count + 1).join(s);
  726. const toInt = (value, radix = 10) => {
  727. const num = parseInt(value, radix);
  728. return isNaN(num) ? Optional.none() : Optional.some(num);
  729. };
  730. const normalVersionRegex = /.*?version\/\ ?([0-9]+)\.([0-9]+).*/;
  731. const checkContains = target => {
  732. return uastring => {
  733. return contains$1(uastring, target);
  734. };
  735. };
  736. const browsers = [
  737. {
  738. name: 'Edge',
  739. versionRegexes: [/.*?edge\/ ?([0-9]+)\.([0-9]+)$/],
  740. search: uastring => {
  741. return contains$1(uastring, 'edge/') && contains$1(uastring, 'chrome') && contains$1(uastring, 'safari') && contains$1(uastring, 'applewebkit');
  742. }
  743. },
  744. {
  745. name: 'Chromium',
  746. brand: 'Chromium',
  747. versionRegexes: [
  748. /.*?chrome\/([0-9]+)\.([0-9]+).*/,
  749. normalVersionRegex
  750. ],
  751. search: uastring => {
  752. return contains$1(uastring, 'chrome') && !contains$1(uastring, 'chromeframe');
  753. }
  754. },
  755. {
  756. name: 'IE',
  757. versionRegexes: [
  758. /.*?msie\ ?([0-9]+)\.([0-9]+).*/,
  759. /.*?rv:([0-9]+)\.([0-9]+).*/
  760. ],
  761. search: uastring => {
  762. return contains$1(uastring, 'msie') || contains$1(uastring, 'trident');
  763. }
  764. },
  765. {
  766. name: 'Opera',
  767. versionRegexes: [
  768. normalVersionRegex,
  769. /.*?opera\/([0-9]+)\.([0-9]+).*/
  770. ],
  771. search: checkContains('opera')
  772. },
  773. {
  774. name: 'Firefox',
  775. versionRegexes: [/.*?firefox\/\ ?([0-9]+)\.([0-9]+).*/],
  776. search: checkContains('firefox')
  777. },
  778. {
  779. name: 'Safari',
  780. versionRegexes: [
  781. normalVersionRegex,
  782. /.*?cpu os ([0-9]+)_([0-9]+).*/
  783. ],
  784. search: uastring => {
  785. return (contains$1(uastring, 'safari') || contains$1(uastring, 'mobile/')) && contains$1(uastring, 'applewebkit');
  786. }
  787. }
  788. ];
  789. const oses = [
  790. {
  791. name: 'Windows',
  792. search: checkContains('win'),
  793. versionRegexes: [/.*?windows\ nt\ ?([0-9]+)\.([0-9]+).*/]
  794. },
  795. {
  796. name: 'iOS',
  797. search: uastring => {
  798. return contains$1(uastring, 'iphone') || contains$1(uastring, 'ipad');
  799. },
  800. versionRegexes: [
  801. /.*?version\/\ ?([0-9]+)\.([0-9]+).*/,
  802. /.*cpu os ([0-9]+)_([0-9]+).*/,
  803. /.*cpu iphone os ([0-9]+)_([0-9]+).*/
  804. ]
  805. },
  806. {
  807. name: 'Android',
  808. search: checkContains('android'),
  809. versionRegexes: [/.*?android\ ?([0-9]+)\.([0-9]+).*/]
  810. },
  811. {
  812. name: 'macOS',
  813. search: checkContains('mac os x'),
  814. versionRegexes: [/.*?mac\ os\ x\ ?([0-9]+)_([0-9]+).*/]
  815. },
  816. {
  817. name: 'Linux',
  818. search: checkContains('linux'),
  819. versionRegexes: []
  820. },
  821. {
  822. name: 'Solaris',
  823. search: checkContains('sunos'),
  824. versionRegexes: []
  825. },
  826. {
  827. name: 'FreeBSD',
  828. search: checkContains('freebsd'),
  829. versionRegexes: []
  830. },
  831. {
  832. name: 'ChromeOS',
  833. search: checkContains('cros'),
  834. versionRegexes: [/.*?chrome\/([0-9]+)\.([0-9]+).*/]
  835. }
  836. ];
  837. const PlatformInfo = {
  838. browsers: constant(browsers),
  839. oses: constant(oses)
  840. };
  841. const edge = 'Edge';
  842. const chromium = 'Chromium';
  843. const ie = 'IE';
  844. const opera = 'Opera';
  845. const firefox = 'Firefox';
  846. const safari = 'Safari';
  847. const unknown$1 = () => {
  848. return nu$2({
  849. current: undefined,
  850. version: Version.unknown()
  851. });
  852. };
  853. const nu$2 = info => {
  854. const current = info.current;
  855. const version = info.version;
  856. const isBrowser = name => () => current === name;
  857. return {
  858. current,
  859. version,
  860. isEdge: isBrowser(edge),
  861. isChromium: isBrowser(chromium),
  862. isIE: isBrowser(ie),
  863. isOpera: isBrowser(opera),
  864. isFirefox: isBrowser(firefox),
  865. isSafari: isBrowser(safari)
  866. };
  867. };
  868. const Browser = {
  869. unknown: unknown$1,
  870. nu: nu$2,
  871. edge: constant(edge),
  872. chromium: constant(chromium),
  873. ie: constant(ie),
  874. opera: constant(opera),
  875. firefox: constant(firefox),
  876. safari: constant(safari)
  877. };
  878. const windows = 'Windows';
  879. const ios = 'iOS';
  880. const android = 'Android';
  881. const linux = 'Linux';
  882. const macos = 'macOS';
  883. const solaris = 'Solaris';
  884. const freebsd = 'FreeBSD';
  885. const chromeos = 'ChromeOS';
  886. const unknown = () => {
  887. return nu$1({
  888. current: undefined,
  889. version: Version.unknown()
  890. });
  891. };
  892. const nu$1 = info => {
  893. const current = info.current;
  894. const version = info.version;
  895. const isOS = name => () => current === name;
  896. return {
  897. current,
  898. version,
  899. isWindows: isOS(windows),
  900. isiOS: isOS(ios),
  901. isAndroid: isOS(android),
  902. isMacOS: isOS(macos),
  903. isLinux: isOS(linux),
  904. isSolaris: isOS(solaris),
  905. isFreeBSD: isOS(freebsd),
  906. isChromeOS: isOS(chromeos)
  907. };
  908. };
  909. const OperatingSystem = {
  910. unknown,
  911. nu: nu$1,
  912. windows: constant(windows),
  913. ios: constant(ios),
  914. android: constant(android),
  915. linux: constant(linux),
  916. macos: constant(macos),
  917. solaris: constant(solaris),
  918. freebsd: constant(freebsd),
  919. chromeos: constant(chromeos)
  920. };
  921. const detect$3 = (userAgent, userAgentDataOpt, mediaMatch) => {
  922. const browsers = PlatformInfo.browsers();
  923. const oses = PlatformInfo.oses();
  924. const browser = userAgentDataOpt.bind(userAgentData => detectBrowser$1(browsers, userAgentData)).orThunk(() => detectBrowser(browsers, userAgent)).fold(Browser.unknown, Browser.nu);
  925. const os = detectOs(oses, userAgent).fold(OperatingSystem.unknown, OperatingSystem.nu);
  926. const deviceType = DeviceType(os, browser, userAgent, mediaMatch);
  927. return {
  928. browser,
  929. os,
  930. deviceType
  931. };
  932. };
  933. const PlatformDetection = { detect: detect$3 };
  934. const mediaMatch = query => window.matchMedia(query).matches;
  935. let platform$2 = cached(() => PlatformDetection.detect(navigator.userAgent, Optional.from(navigator.userAgentData), mediaMatch));
  936. const detect$2 = () => platform$2();
  937. const userAgent = navigator.userAgent;
  938. const platform$1 = detect$2();
  939. const browser$1 = platform$1.browser;
  940. const os = platform$1.os;
  941. const deviceType = platform$1.deviceType;
  942. const windowsPhone = userAgent.indexOf('Windows Phone') !== -1;
  943. const Env = {
  944. transparentSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
  945. documentMode: browser$1.isIE() ? document.documentMode || 7 : 10,
  946. cacheSuffix: null,
  947. container: null,
  948. canHaveCSP: !browser$1.isIE(),
  949. windowsPhone,
  950. browser: {
  951. current: browser$1.current,
  952. version: browser$1.version,
  953. isChromium: browser$1.isChromium,
  954. isEdge: browser$1.isEdge,
  955. isFirefox: browser$1.isFirefox,
  956. isIE: browser$1.isIE,
  957. isOpera: browser$1.isOpera,
  958. isSafari: browser$1.isSafari
  959. },
  960. os: {
  961. current: os.current,
  962. version: os.version,
  963. isAndroid: os.isAndroid,
  964. isChromeOS: os.isChromeOS,
  965. isFreeBSD: os.isFreeBSD,
  966. isiOS: os.isiOS,
  967. isLinux: os.isLinux,
  968. isMacOS: os.isMacOS,
  969. isSolaris: os.isSolaris,
  970. isWindows: os.isWindows
  971. },
  972. deviceType: {
  973. isDesktop: deviceType.isDesktop,
  974. isiPad: deviceType.isiPad,
  975. isiPhone: deviceType.isiPhone,
  976. isPhone: deviceType.isPhone,
  977. isTablet: deviceType.isTablet,
  978. isTouch: deviceType.isTouch,
  979. isWebView: deviceType.isWebView
  980. }
  981. };
  982. const whiteSpaceRegExp$1 = /^\s*|\s*$/g;
  983. const trim$2 = str => {
  984. return isNullable(str) ? '' : ('' + str).replace(whiteSpaceRegExp$1, '');
  985. };
  986. const is$3 = (obj, type) => {
  987. if (!type) {
  988. return obj !== undefined;
  989. }
  990. if (type === 'array' && isArray(obj)) {
  991. return true;
  992. }
  993. return typeof obj === type;
  994. };
  995. const makeMap$4 = (items, delim, map = {}) => {
  996. const resolvedItems = isString(items) ? items.split(delim || ',') : items || [];
  997. let i = resolvedItems.length;
  998. while (i--) {
  999. map[resolvedItems[i]] = {};
  1000. }
  1001. return map;
  1002. };
  1003. const hasOwnProperty$1 = has$2;
  1004. const extend$3 = (obj, ...exts) => {
  1005. for (let i = 0; i < exts.length; i++) {
  1006. const ext = exts[i];
  1007. for (const name in ext) {
  1008. if (has$2(ext, name)) {
  1009. const value = ext[name];
  1010. if (value !== undefined) {
  1011. obj[name] = value;
  1012. }
  1013. }
  1014. }
  1015. }
  1016. return obj;
  1017. };
  1018. const walk$4 = function (o, f, n, s) {
  1019. s = s || this;
  1020. if (o) {
  1021. if (n) {
  1022. o = o[n];
  1023. }
  1024. each$c(o, (o, i) => {
  1025. if (f.call(s, o, i, n) === false) {
  1026. return false;
  1027. } else {
  1028. walk$4(o, f, n, s);
  1029. return true;
  1030. }
  1031. });
  1032. }
  1033. };
  1034. const resolve$2 = (n, o = window) => {
  1035. const path = n.split('.');
  1036. for (let i = 0, l = path.length; i < l; i++) {
  1037. o = o[path[i]];
  1038. if (!o) {
  1039. break;
  1040. }
  1041. }
  1042. return o;
  1043. };
  1044. const explode$3 = (s, d) => {
  1045. if (isArray$1(s)) {
  1046. return s;
  1047. } else if (s === '') {
  1048. return [];
  1049. } else {
  1050. return map$1(s.split(d || ','), trim$2);
  1051. }
  1052. };
  1053. const _addCacheSuffix = url => {
  1054. const cacheSuffix = Env.cacheSuffix;
  1055. if (cacheSuffix) {
  1056. url += (url.indexOf('?') === -1 ? '?' : '&') + cacheSuffix;
  1057. }
  1058. return url;
  1059. };
  1060. const Tools = {
  1061. trim: trim$2,
  1062. isArray: isArray,
  1063. is: is$3,
  1064. toArray: toArray$1,
  1065. makeMap: makeMap$4,
  1066. each: each$c,
  1067. map: map$1,
  1068. grep: filter$3,
  1069. inArray: indexOf,
  1070. hasOwn: hasOwnProperty$1,
  1071. extend: extend$3,
  1072. walk: walk$4,
  1073. resolve: resolve$2,
  1074. explode: explode$3,
  1075. _addCacheSuffix
  1076. };
  1077. const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  1078. const cat = arr => {
  1079. const r = [];
  1080. const push = x => {
  1081. r.push(x);
  1082. };
  1083. for (let i = 0; i < arr.length; i++) {
  1084. arr[i].each(push);
  1085. }
  1086. return r;
  1087. };
  1088. const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  1089. const lift3 = (oa, ob, oc, f) => oa.isSome() && ob.isSome() && oc.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie(), oc.getOrDie())) : Optional.none();
  1090. const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  1091. typeof window !== 'undefined' ? window : Function('return this;')();
  1092. const COMMENT = 8;
  1093. const DOCUMENT = 9;
  1094. const DOCUMENT_FRAGMENT = 11;
  1095. const ELEMENT = 1;
  1096. const TEXT = 3;
  1097. const name = element => {
  1098. const r = element.dom.nodeName;
  1099. return r.toLowerCase();
  1100. };
  1101. const type$1 = element => element.dom.nodeType;
  1102. const isType = t => element => type$1(element) === t;
  1103. const isComment$1 = element => type$1(element) === COMMENT || name(element) === '#comment';
  1104. const isElement$7 = isType(ELEMENT);
  1105. const isText$b = isType(TEXT);
  1106. const isDocument$2 = isType(DOCUMENT);
  1107. const isDocumentFragment$1 = isType(DOCUMENT_FRAGMENT);
  1108. const isTag = tag => e => isElement$7(e) && name(e) === tag;
  1109. const rawSet = (dom, key, value) => {
  1110. if (isString(value) || isBoolean(value) || isNumber(value)) {
  1111. dom.setAttribute(key, value + '');
  1112. } else {
  1113. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  1114. throw new Error('Attribute value was not simple');
  1115. }
  1116. };
  1117. const set$2 = (element, key, value) => {
  1118. rawSet(element.dom, key, value);
  1119. };
  1120. const setAll$1 = (element, attrs) => {
  1121. const dom = element.dom;
  1122. each$d(attrs, (v, k) => {
  1123. rawSet(dom, k, v);
  1124. });
  1125. };
  1126. const get$9 = (element, key) => {
  1127. const v = element.dom.getAttribute(key);
  1128. return v === null ? undefined : v;
  1129. };
  1130. const getOpt = (element, key) => Optional.from(get$9(element, key));
  1131. const has$1 = (element, key) => {
  1132. const dom = element.dom;
  1133. return dom && dom.hasAttribute ? dom.hasAttribute(key) : false;
  1134. };
  1135. const remove$b = (element, key) => {
  1136. element.dom.removeAttribute(key);
  1137. };
  1138. const hasNone = element => {
  1139. const attrs = element.dom.attributes;
  1140. return attrs === undefined || attrs === null || attrs.length === 0;
  1141. };
  1142. const clone$4 = element => foldl(element.dom.attributes, (acc, attr) => {
  1143. acc[attr.name] = attr.value;
  1144. return acc;
  1145. }, {});
  1146. const read$4 = (element, attr) => {
  1147. const value = get$9(element, attr);
  1148. return value === undefined || value === '' ? [] : value.split(' ');
  1149. };
  1150. const add$4 = (element, attr, id) => {
  1151. const old = read$4(element, attr);
  1152. const nu = old.concat([id]);
  1153. set$2(element, attr, nu.join(' '));
  1154. return true;
  1155. };
  1156. const remove$a = (element, attr, id) => {
  1157. const nu = filter$5(read$4(element, attr), v => v !== id);
  1158. if (nu.length > 0) {
  1159. set$2(element, attr, nu.join(' '));
  1160. } else {
  1161. remove$b(element, attr);
  1162. }
  1163. return false;
  1164. };
  1165. const supports = element => element.dom.classList !== undefined;
  1166. const get$8 = element => read$4(element, 'class');
  1167. const add$3 = (element, clazz) => add$4(element, 'class', clazz);
  1168. const remove$9 = (element, clazz) => remove$a(element, 'class', clazz);
  1169. const toggle$2 = (element, clazz) => {
  1170. if (contains$2(get$8(element), clazz)) {
  1171. return remove$9(element, clazz);
  1172. } else {
  1173. return add$3(element, clazz);
  1174. }
  1175. };
  1176. const add$2 = (element, clazz) => {
  1177. if (supports(element)) {
  1178. element.dom.classList.add(clazz);
  1179. } else {
  1180. add$3(element, clazz);
  1181. }
  1182. };
  1183. const cleanClass = element => {
  1184. const classList = supports(element) ? element.dom.classList : get$8(element);
  1185. if (classList.length === 0) {
  1186. remove$b(element, 'class');
  1187. }
  1188. };
  1189. const remove$8 = (element, clazz) => {
  1190. if (supports(element)) {
  1191. const classList = element.dom.classList;
  1192. classList.remove(clazz);
  1193. } else {
  1194. remove$9(element, clazz);
  1195. }
  1196. cleanClass(element);
  1197. };
  1198. const toggle$1 = (element, clazz) => {
  1199. const result = supports(element) ? element.dom.classList.toggle(clazz) : toggle$2(element, clazz);
  1200. cleanClass(element);
  1201. return result;
  1202. };
  1203. const has = (element, clazz) => supports(element) && element.dom.classList.contains(clazz);
  1204. const isSupported$1 = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  1205. const fromHtml$1 = (html, scope) => {
  1206. const doc = scope || document;
  1207. const div = doc.createElement('div');
  1208. div.innerHTML = html;
  1209. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  1210. const message = 'HTML does not have a single root node';
  1211. console.error(message, html);
  1212. throw new Error(message);
  1213. }
  1214. return fromDom$2(div.childNodes[0]);
  1215. };
  1216. const fromTag = (tag, scope) => {
  1217. const doc = scope || document;
  1218. const node = doc.createElement(tag);
  1219. return fromDom$2(node);
  1220. };
  1221. const fromText = (text, scope) => {
  1222. const doc = scope || document;
  1223. const node = doc.createTextNode(text);
  1224. return fromDom$2(node);
  1225. };
  1226. const fromDom$2 = node => {
  1227. if (node === null || node === undefined) {
  1228. throw new Error('Node cannot be null or undefined');
  1229. }
  1230. return { dom: node };
  1231. };
  1232. const fromPoint$2 = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$2);
  1233. const SugarElement = {
  1234. fromHtml: fromHtml$1,
  1235. fromTag,
  1236. fromText,
  1237. fromDom: fromDom$2,
  1238. fromPoint: fromPoint$2
  1239. };
  1240. const toArray = (target, f) => {
  1241. const r = [];
  1242. const recurse = e => {
  1243. r.push(e);
  1244. return f(e);
  1245. };
  1246. let cur = f(target);
  1247. do {
  1248. cur = cur.bind(recurse);
  1249. } while (cur.isSome());
  1250. return r;
  1251. };
  1252. const is$1 = (element, selector) => {
  1253. const dom = element.dom;
  1254. if (dom.nodeType !== ELEMENT) {
  1255. return false;
  1256. } else {
  1257. const elem = dom;
  1258. if (elem.matches !== undefined) {
  1259. return elem.matches(selector);
  1260. } else if (elem.msMatchesSelector !== undefined) {
  1261. return elem.msMatchesSelector(selector);
  1262. } else if (elem.webkitMatchesSelector !== undefined) {
  1263. return elem.webkitMatchesSelector(selector);
  1264. } else if (elem.mozMatchesSelector !== undefined) {
  1265. return elem.mozMatchesSelector(selector);
  1266. } else {
  1267. throw new Error('Browser lacks native selectors');
  1268. }
  1269. }
  1270. };
  1271. const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  1272. const all = (selector, scope) => {
  1273. const base = scope === undefined ? document : scope.dom;
  1274. return bypassSelector(base) ? [] : map$3(base.querySelectorAll(selector), SugarElement.fromDom);
  1275. };
  1276. const one = (selector, scope) => {
  1277. const base = scope === undefined ? document : scope.dom;
  1278. return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
  1279. };
  1280. const eq = (e1, e2) => e1.dom === e2.dom;
  1281. const contains = (e1, e2) => {
  1282. const d1 = e1.dom;
  1283. const d2 = e2.dom;
  1284. return d1 === d2 ? false : d1.contains(d2);
  1285. };
  1286. const owner$1 = element => SugarElement.fromDom(element.dom.ownerDocument);
  1287. const documentOrOwner = dos => isDocument$2(dos) ? dos : owner$1(dos);
  1288. const documentElement = element => SugarElement.fromDom(documentOrOwner(element).dom.documentElement);
  1289. const defaultView = element => SugarElement.fromDom(documentOrOwner(element).dom.defaultView);
  1290. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  1291. const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
  1292. const parents$1 = (element, isRoot) => {
  1293. const stop = isFunction(isRoot) ? isRoot : never;
  1294. let dom = element.dom;
  1295. const ret = [];
  1296. while (dom.parentNode !== null && dom.parentNode !== undefined) {
  1297. const rawParent = dom.parentNode;
  1298. const p = SugarElement.fromDom(rawParent);
  1299. ret.push(p);
  1300. if (stop(p) === true) {
  1301. break;
  1302. } else {
  1303. dom = rawParent;
  1304. }
  1305. }
  1306. return ret;
  1307. };
  1308. const siblings = element => {
  1309. const filterSelf = elements => filter$5(elements, x => !eq(element, x));
  1310. return parent(element).map(children$1).map(filterSelf).getOr([]);
  1311. };
  1312. const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
  1313. const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  1314. const prevSiblings = element => reverse(toArray(element, prevSibling));
  1315. const nextSiblings = element => toArray(element, nextSibling);
  1316. const children$1 = element => map$3(element.dom.childNodes, SugarElement.fromDom);
  1317. const child$1 = (element, index) => {
  1318. const cs = element.dom.childNodes;
  1319. return Optional.from(cs[index]).map(SugarElement.fromDom);
  1320. };
  1321. const firstChild = element => child$1(element, 0);
  1322. const lastChild = element => child$1(element, element.dom.childNodes.length - 1);
  1323. const childNodesCount = element => element.dom.childNodes.length;
  1324. const getHead = doc => {
  1325. const b = doc.dom.head;
  1326. if (b === null || b === undefined) {
  1327. throw new Error('Head is not available yet');
  1328. }
  1329. return SugarElement.fromDom(b);
  1330. };
  1331. const isShadowRoot = dos => isDocumentFragment$1(dos) && isNonNullable(dos.dom.host);
  1332. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  1333. const isSupported = constant(supported);
  1334. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  1335. const getStyleContainer = dos => isShadowRoot(dos) ? dos : getHead(documentOrOwner(dos));
  1336. const getContentContainer = dos => isShadowRoot(dos) ? dos : SugarElement.fromDom(documentOrOwner(dos).dom.body);
  1337. const getShadowRoot = e => {
  1338. const r = getRootNode(e);
  1339. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  1340. };
  1341. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  1342. const getOriginalEventTarget = event => {
  1343. if (isSupported() && isNonNullable(event.target)) {
  1344. const el = SugarElement.fromDom(event.target);
  1345. if (isElement$7(el) && isOpenShadowHost(el)) {
  1346. if (event.composed && event.composedPath) {
  1347. const composedPath = event.composedPath();
  1348. if (composedPath) {
  1349. return head(composedPath);
  1350. }
  1351. }
  1352. }
  1353. }
  1354. return Optional.from(event.target);
  1355. };
  1356. const isOpenShadowHost = element => isNonNullable(element.dom.shadowRoot);
  1357. const inBody = element => {
  1358. const dom = isText$b(element) ? element.dom.parentNode : element.dom;
  1359. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  1360. return false;
  1361. }
  1362. const doc = dom.ownerDocument;
  1363. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  1364. };
  1365. const internalSet = (dom, property, value) => {
  1366. if (!isString(value)) {
  1367. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  1368. throw new Error('CSS value must be a string: ' + value);
  1369. }
  1370. if (isSupported$1(dom)) {
  1371. dom.style.setProperty(property, value);
  1372. }
  1373. };
  1374. const internalRemove = (dom, property) => {
  1375. if (isSupported$1(dom)) {
  1376. dom.style.removeProperty(property);
  1377. }
  1378. };
  1379. const set$1 = (element, property, value) => {
  1380. const dom = element.dom;
  1381. internalSet(dom, property, value);
  1382. };
  1383. const setAll = (element, css) => {
  1384. const dom = element.dom;
  1385. each$d(css, (v, k) => {
  1386. internalSet(dom, k, v);
  1387. });
  1388. };
  1389. const get$7 = (element, property) => {
  1390. const dom = element.dom;
  1391. const styles = window.getComputedStyle(dom);
  1392. const r = styles.getPropertyValue(property);
  1393. return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  1394. };
  1395. const getUnsafeProperty = (dom, property) => isSupported$1(dom) ? dom.style.getPropertyValue(property) : '';
  1396. const getRaw$1 = (element, property) => {
  1397. const dom = element.dom;
  1398. const raw = getUnsafeProperty(dom, property);
  1399. return Optional.from(raw).filter(r => r.length > 0);
  1400. };
  1401. const getAllRaw = element => {
  1402. const css = {};
  1403. const dom = element.dom;
  1404. if (isSupported$1(dom)) {
  1405. for (let i = 0; i < dom.style.length; i++) {
  1406. const ruleName = dom.style.item(i);
  1407. css[ruleName] = dom.style[ruleName];
  1408. }
  1409. }
  1410. return css;
  1411. };
  1412. const remove$7 = (element, property) => {
  1413. const dom = element.dom;
  1414. internalRemove(dom, property);
  1415. if (is$2(getOpt(element, 'style').map(trim$3), '')) {
  1416. remove$b(element, 'style');
  1417. }
  1418. };
  1419. const reflow = e => e.dom.offsetWidth;
  1420. const before$3 = (marker, element) => {
  1421. const parent$1 = parent(marker);
  1422. parent$1.each(v => {
  1423. v.dom.insertBefore(element.dom, marker.dom);
  1424. });
  1425. };
  1426. const after$4 = (marker, element) => {
  1427. const sibling = nextSibling(marker);
  1428. sibling.fold(() => {
  1429. const parent$1 = parent(marker);
  1430. parent$1.each(v => {
  1431. append$1(v, element);
  1432. });
  1433. }, v => {
  1434. before$3(v, element);
  1435. });
  1436. };
  1437. const prepend = (parent, element) => {
  1438. const firstChild$1 = firstChild(parent);
  1439. firstChild$1.fold(() => {
  1440. append$1(parent, element);
  1441. }, v => {
  1442. parent.dom.insertBefore(element.dom, v.dom);
  1443. });
  1444. };
  1445. const append$1 = (parent, element) => {
  1446. parent.dom.appendChild(element.dom);
  1447. };
  1448. const wrap$2 = (element, wrapper) => {
  1449. before$3(element, wrapper);
  1450. append$1(wrapper, element);
  1451. };
  1452. const after$3 = (marker, elements) => {
  1453. each$e(elements, (x, i) => {
  1454. const e = i === 0 ? marker : elements[i - 1];
  1455. after$4(e, x);
  1456. });
  1457. };
  1458. const append = (parent, elements) => {
  1459. each$e(elements, x => {
  1460. append$1(parent, x);
  1461. });
  1462. };
  1463. const empty = element => {
  1464. element.dom.textContent = '';
  1465. each$e(children$1(element), rogue => {
  1466. remove$6(rogue);
  1467. });
  1468. };
  1469. const remove$6 = element => {
  1470. const dom = element.dom;
  1471. if (dom.parentNode !== null) {
  1472. dom.parentNode.removeChild(dom);
  1473. }
  1474. };
  1475. const unwrap = wrapper => {
  1476. const children = children$1(wrapper);
  1477. if (children.length > 0) {
  1478. after$3(wrapper, children);
  1479. }
  1480. remove$6(wrapper);
  1481. };
  1482. const fromHtml = (html, scope) => {
  1483. const doc = scope || document;
  1484. const div = doc.createElement('div');
  1485. div.innerHTML = html;
  1486. return children$1(SugarElement.fromDom(div));
  1487. };
  1488. const fromDom$1 = nodes => map$3(nodes, SugarElement.fromDom);
  1489. const get$6 = element => element.dom.innerHTML;
  1490. const set = (element, content) => {
  1491. const owner = owner$1(element);
  1492. const docDom = owner.dom;
  1493. const fragment = SugarElement.fromDom(docDom.createDocumentFragment());
  1494. const contentElements = fromHtml(content, docDom);
  1495. append(fragment, contentElements);
  1496. empty(element);
  1497. append$1(element, fragment);
  1498. };
  1499. const getOuter = element => {
  1500. const container = SugarElement.fromTag('div');
  1501. const clone = SugarElement.fromDom(element.dom.cloneNode(true));
  1502. append$1(container, clone);
  1503. return get$6(container);
  1504. };
  1505. const mkEvent = (target, x, y, stop, prevent, kill, raw) => ({
  1506. target,
  1507. x,
  1508. y,
  1509. stop,
  1510. prevent,
  1511. kill,
  1512. raw
  1513. });
  1514. const fromRawEvent = rawEvent => {
  1515. const target = SugarElement.fromDom(getOriginalEventTarget(rawEvent).getOr(rawEvent.target));
  1516. const stop = () => rawEvent.stopPropagation();
  1517. const prevent = () => rawEvent.preventDefault();
  1518. const kill = compose(prevent, stop);
  1519. return mkEvent(target, rawEvent.clientX, rawEvent.clientY, stop, prevent, kill, rawEvent);
  1520. };
  1521. const handle$1 = (filter, handler) => rawEvent => {
  1522. if (filter(rawEvent)) {
  1523. handler(fromRawEvent(rawEvent));
  1524. }
  1525. };
  1526. const binder = (element, event, filter, handler, useCapture) => {
  1527. const wrapped = handle$1(filter, handler);
  1528. element.dom.addEventListener(event, wrapped, useCapture);
  1529. return { unbind: curry(unbind, element, event, wrapped, useCapture) };
  1530. };
  1531. const bind$2 = (element, event, filter, handler) => binder(element, event, filter, handler, false);
  1532. const unbind = (element, event, handler, useCapture) => {
  1533. element.dom.removeEventListener(event, handler, useCapture);
  1534. };
  1535. const r = (left, top) => {
  1536. const translate = (x, y) => r(left + x, top + y);
  1537. return {
  1538. left,
  1539. top,
  1540. translate
  1541. };
  1542. };
  1543. const SugarPosition = r;
  1544. const boxPosition = dom => {
  1545. const box = dom.getBoundingClientRect();
  1546. return SugarPosition(box.left, box.top);
  1547. };
  1548. const firstDefinedOrZero = (a, b) => {
  1549. if (a !== undefined) {
  1550. return a;
  1551. } else {
  1552. return b !== undefined ? b : 0;
  1553. }
  1554. };
  1555. const absolute = element => {
  1556. const doc = element.dom.ownerDocument;
  1557. const body = doc.body;
  1558. const win = doc.defaultView;
  1559. const html = doc.documentElement;
  1560. if (body === element.dom) {
  1561. return SugarPosition(body.offsetLeft, body.offsetTop);
  1562. }
  1563. const scrollTop = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageYOffset, html.scrollTop);
  1564. const scrollLeft = firstDefinedOrZero(win === null || win === void 0 ? void 0 : win.pageXOffset, html.scrollLeft);
  1565. const clientTop = firstDefinedOrZero(html.clientTop, body.clientTop);
  1566. const clientLeft = firstDefinedOrZero(html.clientLeft, body.clientLeft);
  1567. return viewport(element).translate(scrollLeft - clientLeft, scrollTop - clientTop);
  1568. };
  1569. const viewport = element => {
  1570. const dom = element.dom;
  1571. const doc = dom.ownerDocument;
  1572. const body = doc.body;
  1573. if (body === dom) {
  1574. return SugarPosition(body.offsetLeft, body.offsetTop);
  1575. }
  1576. if (!inBody(element)) {
  1577. return SugarPosition(0, 0);
  1578. }
  1579. return boxPosition(dom);
  1580. };
  1581. const get$5 = _DOC => {
  1582. const doc = _DOC !== undefined ? _DOC.dom : document;
  1583. const x = doc.body.scrollLeft || doc.documentElement.scrollLeft;
  1584. const y = doc.body.scrollTop || doc.documentElement.scrollTop;
  1585. return SugarPosition(x, y);
  1586. };
  1587. const to = (x, y, _DOC) => {
  1588. const doc = _DOC !== undefined ? _DOC.dom : document;
  1589. const win = doc.defaultView;
  1590. if (win) {
  1591. win.scrollTo(x, y);
  1592. }
  1593. };
  1594. const intoView = (element, alignToTop) => {
  1595. const isSafari = detect$2().browser.isSafari();
  1596. if (isSafari && isFunction(element.dom.scrollIntoViewIfNeeded)) {
  1597. element.dom.scrollIntoViewIfNeeded(false);
  1598. } else {
  1599. element.dom.scrollIntoView(alignToTop);
  1600. }
  1601. };
  1602. const get$4 = _win => {
  1603. const win = _win === undefined ? window : _win;
  1604. if (detect$2().browser.isFirefox()) {
  1605. return Optional.none();
  1606. } else {
  1607. return Optional.from(win.visualViewport);
  1608. }
  1609. };
  1610. const bounds = (x, y, width, height) => ({
  1611. x,
  1612. y,
  1613. width,
  1614. height,
  1615. right: x + width,
  1616. bottom: y + height
  1617. });
  1618. const getBounds = _win => {
  1619. const win = _win === undefined ? window : _win;
  1620. const doc = win.document;
  1621. const scroll = get$5(SugarElement.fromDom(doc));
  1622. return get$4(win).fold(() => {
  1623. const html = win.document.documentElement;
  1624. const width = html.clientWidth;
  1625. const height = html.clientHeight;
  1626. return bounds(scroll.left, scroll.top, width, height);
  1627. }, visualViewport => bounds(Math.max(visualViewport.pageLeft, scroll.left), Math.max(visualViewport.pageTop, scroll.top), visualViewport.width, visualViewport.height));
  1628. };
  1629. const children = (scope, predicate) => filter$5(children$1(scope), predicate);
  1630. const descendants$1 = (scope, predicate) => {
  1631. let result = [];
  1632. each$e(children$1(scope), x => {
  1633. if (predicate(x)) {
  1634. result = result.concat([x]);
  1635. }
  1636. result = result.concat(descendants$1(x, predicate));
  1637. });
  1638. return result;
  1639. };
  1640. var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
  1641. if (is(scope, a)) {
  1642. return Optional.some(scope);
  1643. } else if (isFunction(isRoot) && isRoot(scope)) {
  1644. return Optional.none();
  1645. } else {
  1646. return ancestor(scope, a, isRoot);
  1647. }
  1648. };
  1649. const ancestor$3 = (scope, predicate, isRoot) => {
  1650. let element = scope.dom;
  1651. const stop = isFunction(isRoot) ? isRoot : never;
  1652. while (element.parentNode) {
  1653. element = element.parentNode;
  1654. const el = SugarElement.fromDom(element);
  1655. if (predicate(el)) {
  1656. return Optional.some(el);
  1657. } else if (stop(el)) {
  1658. break;
  1659. }
  1660. }
  1661. return Optional.none();
  1662. };
  1663. const closest$4 = (scope, predicate, isRoot) => {
  1664. const is = (s, test) => test(s);
  1665. return ClosestOrAncestor(is, ancestor$3, scope, predicate, isRoot);
  1666. };
  1667. const sibling$1 = (scope, predicate) => {
  1668. const element = scope.dom;
  1669. if (!element.parentNode) {
  1670. return Optional.none();
  1671. }
  1672. return child(SugarElement.fromDom(element.parentNode), x => !eq(scope, x) && predicate(x));
  1673. };
  1674. const child = (scope, predicate) => {
  1675. const pred = node => predicate(SugarElement.fromDom(node));
  1676. const result = find$2(scope.dom.childNodes, pred);
  1677. return result.map(SugarElement.fromDom);
  1678. };
  1679. const descendant$1 = (scope, predicate) => {
  1680. const descend = node => {
  1681. for (let i = 0; i < node.childNodes.length; i++) {
  1682. const child = SugarElement.fromDom(node.childNodes[i]);
  1683. if (predicate(child)) {
  1684. return Optional.some(child);
  1685. }
  1686. const res = descend(node.childNodes[i]);
  1687. if (res.isSome()) {
  1688. return res;
  1689. }
  1690. }
  1691. return Optional.none();
  1692. };
  1693. return descend(scope.dom);
  1694. };
  1695. const ancestor$2 = (scope, selector, isRoot) => ancestor$3(scope, e => is$1(e, selector), isRoot);
  1696. const descendant = (scope, selector) => one(selector, scope);
  1697. const closest$3 = (scope, selector, isRoot) => {
  1698. const is = (element, selector) => is$1(element, selector);
  1699. return ClosestOrAncestor(is, ancestor$2, scope, selector, isRoot);
  1700. };
  1701. const ancestor$1 = (scope, selector, isRoot) => ancestor$2(scope, selector, isRoot).isSome();
  1702. class DomTreeWalker {
  1703. constructor(startNode, rootNode) {
  1704. this.node = startNode;
  1705. this.rootNode = rootNode;
  1706. this.current = this.current.bind(this);
  1707. this.next = this.next.bind(this);
  1708. this.prev = this.prev.bind(this);
  1709. this.prev2 = this.prev2.bind(this);
  1710. }
  1711. current() {
  1712. return this.node;
  1713. }
  1714. next(shallow) {
  1715. this.node = this.findSibling(this.node, 'firstChild', 'nextSibling', shallow);
  1716. return this.node;
  1717. }
  1718. prev(shallow) {
  1719. this.node = this.findSibling(this.node, 'lastChild', 'previousSibling', shallow);
  1720. return this.node;
  1721. }
  1722. prev2(shallow) {
  1723. this.node = this.findPreviousNode(this.node, shallow);
  1724. return this.node;
  1725. }
  1726. findSibling(node, startName, siblingName, shallow) {
  1727. if (node) {
  1728. if (!shallow && node[startName]) {
  1729. return node[startName];
  1730. }
  1731. if (node !== this.rootNode) {
  1732. let sibling = node[siblingName];
  1733. if (sibling) {
  1734. return sibling;
  1735. }
  1736. for (let parent = node.parentNode; parent && parent !== this.rootNode; parent = parent.parentNode) {
  1737. sibling = parent[siblingName];
  1738. if (sibling) {
  1739. return sibling;
  1740. }
  1741. }
  1742. }
  1743. }
  1744. return undefined;
  1745. }
  1746. findPreviousNode(node, shallow) {
  1747. if (node) {
  1748. const sibling = node.previousSibling;
  1749. if (this.rootNode && sibling === this.rootNode) {
  1750. return;
  1751. }
  1752. if (sibling) {
  1753. if (!shallow) {
  1754. for (let child = sibling.lastChild; child; child = child.lastChild) {
  1755. if (!child.lastChild) {
  1756. return child;
  1757. }
  1758. }
  1759. }
  1760. return sibling;
  1761. }
  1762. const parent = node.parentNode;
  1763. if (parent && parent !== this.rootNode) {
  1764. return parent;
  1765. }
  1766. }
  1767. return undefined;
  1768. }
  1769. }
  1770. const isNodeType = type => {
  1771. return node => {
  1772. return !!node && node.nodeType === type;
  1773. };
  1774. };
  1775. const isRestrictedNode = node => !!node && !Object.getPrototypeOf(node);
  1776. const isElement$6 = isNodeType(1);
  1777. const matchNodeName = name => {
  1778. const lowerCasedName = name.toLowerCase();
  1779. return node => isNonNullable(node) && node.nodeName.toLowerCase() === lowerCasedName;
  1780. };
  1781. const matchNodeNames = names => {
  1782. const lowerCasedNames = names.map(s => s.toLowerCase());
  1783. return node => {
  1784. if (node && node.nodeName) {
  1785. const nodeName = node.nodeName.toLowerCase();
  1786. return contains$2(lowerCasedNames, nodeName);
  1787. }
  1788. return false;
  1789. };
  1790. };
  1791. const matchStyleValues = (name, values) => {
  1792. const items = values.toLowerCase().split(' ');
  1793. return node => {
  1794. if (isElement$6(node)) {
  1795. const win = node.ownerDocument.defaultView;
  1796. if (win) {
  1797. for (let i = 0; i < items.length; i++) {
  1798. const computed = win.getComputedStyle(node, null);
  1799. const cssValue = computed ? computed.getPropertyValue(name) : null;
  1800. if (cssValue === items[i]) {
  1801. return true;
  1802. }
  1803. }
  1804. }
  1805. }
  1806. return false;
  1807. };
  1808. };
  1809. const hasAttribute = attrName => {
  1810. return node => {
  1811. return isElement$6(node) && node.hasAttribute(attrName);
  1812. };
  1813. };
  1814. const hasAttributeValue = (attrName, attrValue) => {
  1815. return node => {
  1816. return isElement$6(node) && node.getAttribute(attrName) === attrValue;
  1817. };
  1818. };
  1819. const isBogus$2 = node => isElement$6(node) && node.hasAttribute('data-mce-bogus');
  1820. const isBogusAll$1 = node => isElement$6(node) && node.getAttribute('data-mce-bogus') === 'all';
  1821. const isTable$2 = node => isElement$6(node) && node.tagName === 'TABLE';
  1822. const hasContentEditableState = value => {
  1823. return node => {
  1824. if (isElement$6(node)) {
  1825. if (node.contentEditable === value) {
  1826. return true;
  1827. }
  1828. if (node.getAttribute('data-mce-contenteditable') === value) {
  1829. return true;
  1830. }
  1831. }
  1832. return false;
  1833. };
  1834. };
  1835. const isTextareaOrInput = matchNodeNames([
  1836. 'textarea',
  1837. 'input'
  1838. ]);
  1839. const isText$a = isNodeType(3);
  1840. const isCData = isNodeType(4);
  1841. const isPi = isNodeType(7);
  1842. const isComment = isNodeType(8);
  1843. const isDocument$1 = isNodeType(9);
  1844. const isDocumentFragment = isNodeType(11);
  1845. const isBr$6 = matchNodeName('br');
  1846. const isImg = matchNodeName('img');
  1847. const isContentEditableTrue$3 = hasContentEditableState('true');
  1848. const isContentEditableFalse$a = hasContentEditableState('false');
  1849. const isTableCell$3 = matchNodeNames([
  1850. 'td',
  1851. 'th'
  1852. ]);
  1853. const isTableCellOrCaption = matchNodeNames([
  1854. 'td',
  1855. 'th',
  1856. 'caption'
  1857. ]);
  1858. const isMedia$2 = matchNodeNames([
  1859. 'video',
  1860. 'audio',
  1861. 'object',
  1862. 'embed'
  1863. ]);
  1864. const isListItem$2 = matchNodeName('li');
  1865. const zeroWidth = '\uFEFF';
  1866. const nbsp = '\xA0';
  1867. const isZwsp$1 = char => char === zeroWidth;
  1868. const removeZwsp = s => s.replace(/\uFEFF/g, '');
  1869. const descendants = (scope, selector) => all(selector, scope);
  1870. const NodeValue = (is, name) => {
  1871. const get = element => {
  1872. if (!is(element)) {
  1873. throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
  1874. }
  1875. return getOption(element).getOr('');
  1876. };
  1877. const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
  1878. const set = (element, value) => {
  1879. if (!is(element)) {
  1880. throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
  1881. }
  1882. element.dom.nodeValue = value;
  1883. };
  1884. return {
  1885. get,
  1886. getOption,
  1887. set
  1888. };
  1889. };
  1890. const api$1 = NodeValue(isText$b, 'text');
  1891. const get$3 = element => api$1.get(element);
  1892. const getOption = element => api$1.getOption(element);
  1893. const blocks = [
  1894. 'article',
  1895. 'aside',
  1896. 'details',
  1897. 'div',
  1898. 'dt',
  1899. 'figcaption',
  1900. 'footer',
  1901. 'form',
  1902. 'fieldset',
  1903. 'header',
  1904. 'hgroup',
  1905. 'html',
  1906. 'main',
  1907. 'nav',
  1908. 'section',
  1909. 'summary',
  1910. 'body',
  1911. 'p',
  1912. 'dl',
  1913. 'multicol',
  1914. 'dd',
  1915. 'figure',
  1916. 'address',
  1917. 'center',
  1918. 'blockquote',
  1919. 'h1',
  1920. 'h2',
  1921. 'h3',
  1922. 'h4',
  1923. 'h5',
  1924. 'h6',
  1925. 'listing',
  1926. 'xmp',
  1927. 'pre',
  1928. 'plaintext',
  1929. 'menu',
  1930. 'dir',
  1931. 'ul',
  1932. 'ol',
  1933. 'li',
  1934. 'hr',
  1935. 'table',
  1936. 'tbody',
  1937. 'thead',
  1938. 'tfoot',
  1939. 'th',
  1940. 'tr',
  1941. 'td',
  1942. 'caption'
  1943. ];
  1944. const tableCells = [
  1945. 'td',
  1946. 'th'
  1947. ];
  1948. const tableSections = [
  1949. 'thead',
  1950. 'tbody',
  1951. 'tfoot'
  1952. ];
  1953. const textBlocks = [
  1954. 'h1',
  1955. 'h2',
  1956. 'h3',
  1957. 'h4',
  1958. 'h5',
  1959. 'h6',
  1960. 'p',
  1961. 'div',
  1962. 'address',
  1963. 'pre',
  1964. 'form',
  1965. 'blockquote',
  1966. 'center',
  1967. 'dir',
  1968. 'fieldset',
  1969. 'header',
  1970. 'footer',
  1971. 'article',
  1972. 'section',
  1973. 'hgroup',
  1974. 'aside',
  1975. 'nav',
  1976. 'figure'
  1977. ];
  1978. const headings = [
  1979. 'h1',
  1980. 'h2',
  1981. 'h3',
  1982. 'h4',
  1983. 'h5',
  1984. 'h6'
  1985. ];
  1986. const listItems$1 = [
  1987. 'li',
  1988. 'dd',
  1989. 'dt'
  1990. ];
  1991. const lists = [
  1992. 'ul',
  1993. 'ol',
  1994. 'dl'
  1995. ];
  1996. const wsElements = [
  1997. 'pre',
  1998. 'script',
  1999. 'textarea',
  2000. 'style'
  2001. ];
  2002. const wrapBlockElements = ['pre'].concat(headings);
  2003. const lazyLookup = items => {
  2004. let lookup;
  2005. return node => {
  2006. lookup = lookup ? lookup : mapToObject(items, always);
  2007. return has$2(lookup, name(node));
  2008. };
  2009. };
  2010. const isBlock$2 = lazyLookup(blocks);
  2011. const isTable$1 = node => name(node) === 'table';
  2012. const isInline$1 = node => isElement$7(node) && !isBlock$2(node);
  2013. const isBr$5 = node => isElement$7(node) && name(node) === 'br';
  2014. const isTextBlock$2 = lazyLookup(textBlocks);
  2015. const isList = lazyLookup(lists);
  2016. const isListItem$1 = lazyLookup(listItems$1);
  2017. const isTableSection = lazyLookup(tableSections);
  2018. const isTableCell$2 = lazyLookup(tableCells);
  2019. const isWsPreserveElement = lazyLookup(wsElements);
  2020. const isWrapBlockElement = lazyLookup(wrapBlockElements);
  2021. const isWrapElement = node => isWrapBlockElement(node) || isInline$1(node);
  2022. const getLastChildren$1 = elm => {
  2023. const children = [];
  2024. let rawNode = elm.dom;
  2025. while (rawNode) {
  2026. children.push(SugarElement.fromDom(rawNode));
  2027. rawNode = rawNode.lastChild;
  2028. }
  2029. return children;
  2030. };
  2031. const removeTrailingBr = elm => {
  2032. const allBrs = descendants(elm, 'br');
  2033. const brs = filter$5(getLastChildren$1(elm).slice(-1), isBr$5);
  2034. if (allBrs.length === brs.length) {
  2035. each$e(brs, remove$6);
  2036. }
  2037. };
  2038. const createPaddingBr = () => {
  2039. const br = SugarElement.fromTag('br');
  2040. set$2(br, 'data-mce-bogus', '1');
  2041. return br;
  2042. };
  2043. const fillWithPaddingBr = elm => {
  2044. empty(elm);
  2045. append$1(elm, createPaddingBr());
  2046. };
  2047. const trimBlockTrailingBr = elm => {
  2048. lastChild(elm).each(lastChild => {
  2049. prevSibling(lastChild).each(lastChildPrevSibling => {
  2050. if (isBlock$2(elm) && isBr$5(lastChild) && isBlock$2(lastChildPrevSibling)) {
  2051. remove$6(lastChild);
  2052. }
  2053. });
  2054. });
  2055. };
  2056. const ZWSP$1 = zeroWidth;
  2057. const isZwsp = isZwsp$1;
  2058. const trim$1 = removeZwsp;
  2059. const isElement$5 = isElement$6;
  2060. const isText$9 = isText$a;
  2061. const isCaretContainerBlock$1 = node => {
  2062. if (isText$9(node)) {
  2063. node = node.parentNode;
  2064. }
  2065. return isElement$5(node) && node.hasAttribute('data-mce-caret');
  2066. };
  2067. const isCaretContainerInline = node => isText$9(node) && isZwsp(node.data);
  2068. const isCaretContainer$2 = node => isCaretContainerBlock$1(node) || isCaretContainerInline(node);
  2069. const hasContent = node => node.firstChild !== node.lastChild || !isBr$6(node.firstChild);
  2070. const insertInline$1 = (node, before) => {
  2071. var _a;
  2072. const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
  2073. const textNode = doc.createTextNode(ZWSP$1);
  2074. const parentNode = node.parentNode;
  2075. if (!before) {
  2076. const sibling = node.nextSibling;
  2077. if (isText$9(sibling)) {
  2078. if (isCaretContainer$2(sibling)) {
  2079. return sibling;
  2080. }
  2081. if (startsWithCaretContainer$1(sibling)) {
  2082. sibling.splitText(1);
  2083. return sibling;
  2084. }
  2085. }
  2086. if (node.nextSibling) {
  2087. parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node.nextSibling);
  2088. } else {
  2089. parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(textNode);
  2090. }
  2091. } else {
  2092. const sibling = node.previousSibling;
  2093. if (isText$9(sibling)) {
  2094. if (isCaretContainer$2(sibling)) {
  2095. return sibling;
  2096. }
  2097. if (endsWithCaretContainer$1(sibling)) {
  2098. return sibling.splitText(sibling.data.length - 1);
  2099. }
  2100. }
  2101. parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(textNode, node);
  2102. }
  2103. return textNode;
  2104. };
  2105. const isBeforeInline = pos => {
  2106. const container = pos.container();
  2107. if (!isText$a(container)) {
  2108. return false;
  2109. }
  2110. return container.data.charAt(pos.offset()) === ZWSP$1 || pos.isAtStart() && isCaretContainerInline(container.previousSibling);
  2111. };
  2112. const isAfterInline = pos => {
  2113. const container = pos.container();
  2114. if (!isText$a(container)) {
  2115. return false;
  2116. }
  2117. return container.data.charAt(pos.offset() - 1) === ZWSP$1 || pos.isAtEnd() && isCaretContainerInline(container.nextSibling);
  2118. };
  2119. const insertBlock = (blockName, node, before) => {
  2120. var _a;
  2121. const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
  2122. const blockNode = doc.createElement(blockName);
  2123. blockNode.setAttribute('data-mce-caret', before ? 'before' : 'after');
  2124. blockNode.setAttribute('data-mce-bogus', 'all');
  2125. blockNode.appendChild(createPaddingBr().dom);
  2126. const parentNode = node.parentNode;
  2127. if (!before) {
  2128. if (node.nextSibling) {
  2129. parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node.nextSibling);
  2130. } else {
  2131. parentNode === null || parentNode === void 0 ? void 0 : parentNode.appendChild(blockNode);
  2132. }
  2133. } else {
  2134. parentNode === null || parentNode === void 0 ? void 0 : parentNode.insertBefore(blockNode, node);
  2135. }
  2136. return blockNode;
  2137. };
  2138. const startsWithCaretContainer$1 = node => isText$9(node) && node.data[0] === ZWSP$1;
  2139. const endsWithCaretContainer$1 = node => isText$9(node) && node.data[node.data.length - 1] === ZWSP$1;
  2140. const trimBogusBr = elm => {
  2141. var _a;
  2142. const brs = elm.getElementsByTagName('br');
  2143. const lastBr = brs[brs.length - 1];
  2144. if (isBogus$2(lastBr)) {
  2145. (_a = lastBr.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(lastBr);
  2146. }
  2147. };
  2148. const showCaretContainerBlock = caretContainer => {
  2149. if (caretContainer && caretContainer.hasAttribute('data-mce-caret')) {
  2150. trimBogusBr(caretContainer);
  2151. caretContainer.removeAttribute('data-mce-caret');
  2152. caretContainer.removeAttribute('data-mce-bogus');
  2153. caretContainer.removeAttribute('style');
  2154. caretContainer.removeAttribute('data-mce-style');
  2155. caretContainer.removeAttribute('_moz_abspos');
  2156. return caretContainer;
  2157. }
  2158. return null;
  2159. };
  2160. const isRangeInCaretContainerBlock = range => isCaretContainerBlock$1(range.startContainer);
  2161. const isContentEditableTrue$2 = isContentEditableTrue$3;
  2162. const isContentEditableFalse$9 = isContentEditableFalse$a;
  2163. const isBr$4 = isBr$6;
  2164. const isText$8 = isText$a;
  2165. const isInvalidTextElement = matchNodeNames([
  2166. 'script',
  2167. 'style',
  2168. 'textarea'
  2169. ]);
  2170. const isAtomicInline = matchNodeNames([
  2171. 'img',
  2172. 'input',
  2173. 'textarea',
  2174. 'hr',
  2175. 'iframe',
  2176. 'video',
  2177. 'audio',
  2178. 'object',
  2179. 'embed'
  2180. ]);
  2181. const isTable = matchNodeNames(['table']);
  2182. const isCaretContainer$1 = isCaretContainer$2;
  2183. const isCaretCandidate$3 = node => {
  2184. if (isCaretContainer$1(node)) {
  2185. return false;
  2186. }
  2187. if (isText$8(node)) {
  2188. return !isInvalidTextElement(node.parentNode);
  2189. }
  2190. return isAtomicInline(node) || isBr$4(node) || isTable(node) || isNonUiContentEditableFalse(node);
  2191. };
  2192. const isUnselectable = node => isElement$6(node) && node.getAttribute('unselectable') === 'true';
  2193. const isNonUiContentEditableFalse = node => !isUnselectable(node) && isContentEditableFalse$9(node);
  2194. const isInEditable = (node, root) => {
  2195. for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
  2196. if (isNonUiContentEditableFalse(tempNode)) {
  2197. return false;
  2198. }
  2199. if (isContentEditableTrue$2(tempNode)) {
  2200. return true;
  2201. }
  2202. }
  2203. return true;
  2204. };
  2205. const isAtomicContentEditableFalse = node => {
  2206. if (!isNonUiContentEditableFalse(node)) {
  2207. return false;
  2208. }
  2209. return !foldl(from(node.getElementsByTagName('*')), (result, elm) => {
  2210. return result || isContentEditableTrue$2(elm);
  2211. }, false);
  2212. };
  2213. const isAtomic$1 = node => isAtomicInline(node) || isAtomicContentEditableFalse(node);
  2214. const isEditableCaretCandidate$1 = (node, root) => isCaretCandidate$3(node) && isInEditable(node, root);
  2215. const whiteSpaceRegExp = /^[ \t\r\n]*$/;
  2216. const isWhitespaceText = text => whiteSpaceRegExp.test(text);
  2217. const isCollapsibleWhitespace$1 = c => ' \f\t\x0B'.indexOf(c) !== -1;
  2218. const isNewLineChar = c => c === '\n' || c === '\r';
  2219. const isNewline = (text, idx) => idx < text.length && idx >= 0 ? isNewLineChar(text[idx]) : false;
  2220. const normalize$4 = (text, tabSpaces = 4, isStartOfContent = true, isEndOfContent = true) => {
  2221. const tabSpace = repeat(' ', tabSpaces);
  2222. const normalizedText = text.replace(/\t/g, tabSpace);
  2223. const result = foldl(normalizedText, (acc, c) => {
  2224. if (isCollapsibleWhitespace$1(c) || c === nbsp) {
  2225. if (acc.pcIsSpace || acc.str === '' && isStartOfContent || acc.str.length === normalizedText.length - 1 && isEndOfContent || isNewline(normalizedText, acc.str.length + 1)) {
  2226. return {
  2227. pcIsSpace: false,
  2228. str: acc.str + nbsp
  2229. };
  2230. } else {
  2231. return {
  2232. pcIsSpace: true,
  2233. str: acc.str + ' '
  2234. };
  2235. }
  2236. } else {
  2237. return {
  2238. pcIsSpace: isNewLineChar(c),
  2239. str: acc.str + c
  2240. };
  2241. }
  2242. }, {
  2243. pcIsSpace: false,
  2244. str: ''
  2245. });
  2246. return result.str;
  2247. };
  2248. const hasWhitespacePreserveParent = (node, rootNode) => {
  2249. const rootElement = SugarElement.fromDom(rootNode);
  2250. const startNode = SugarElement.fromDom(node);
  2251. return ancestor$1(startNode, 'pre,code', curry(eq, rootElement));
  2252. };
  2253. const isWhitespace$1 = (node, rootNode) => {
  2254. return isText$a(node) && isWhitespaceText(node.data) && !hasWhitespacePreserveParent(node, rootNode);
  2255. };
  2256. const isNamedAnchor = node => {
  2257. return isElement$6(node) && node.nodeName === 'A' && !node.hasAttribute('href') && (node.hasAttribute('name') || node.hasAttribute('id'));
  2258. };
  2259. const isContent$1 = (node, rootNode) => {
  2260. return isCaretCandidate$3(node) && !isWhitespace$1(node, rootNode) || isNamedAnchor(node) || isBookmark(node);
  2261. };
  2262. const isBookmark = hasAttribute('data-mce-bookmark');
  2263. const isBogus$1 = hasAttribute('data-mce-bogus');
  2264. const isBogusAll = hasAttributeValue('data-mce-bogus', 'all');
  2265. const isEmptyNode = (targetNode, skipBogus) => {
  2266. let brCount = 0;
  2267. if (isContent$1(targetNode, targetNode)) {
  2268. return false;
  2269. } else {
  2270. let node = targetNode.firstChild;
  2271. if (!node) {
  2272. return true;
  2273. }
  2274. const walker = new DomTreeWalker(node, targetNode);
  2275. do {
  2276. if (skipBogus) {
  2277. if (isBogusAll(node)) {
  2278. node = walker.next(true);
  2279. continue;
  2280. }
  2281. if (isBogus$1(node)) {
  2282. node = walker.next();
  2283. continue;
  2284. }
  2285. }
  2286. if (isBr$6(node)) {
  2287. brCount++;
  2288. node = walker.next();
  2289. continue;
  2290. }
  2291. if (isContent$1(node, targetNode)) {
  2292. return false;
  2293. }
  2294. node = walker.next();
  2295. } while (node);
  2296. return brCount <= 1;
  2297. }
  2298. };
  2299. const isEmpty$2 = (elm, skipBogus = true) => isEmptyNode(elm.dom, skipBogus);
  2300. const transparentBlockAttr = 'data-mce-block';
  2301. const elementNames = map => filter$5(keys(map), key => !/[A-Z]/.test(key));
  2302. const makeSelectorFromSchemaMap = map => elementNames(map).join(',');
  2303. const updateTransparent = (blocksSelector, transparent) => {
  2304. if (isNonNullable(transparent.querySelector(blocksSelector))) {
  2305. transparent.setAttribute(transparentBlockAttr, 'true');
  2306. if (transparent.getAttribute('data-mce-selected') === 'inline-boundary') {
  2307. transparent.removeAttribute('data-mce-selected');
  2308. }
  2309. return true;
  2310. } else {
  2311. transparent.removeAttribute(transparentBlockAttr);
  2312. return false;
  2313. }
  2314. };
  2315. const updateBlockStateOnChildren = (schema, scope) => {
  2316. const transparentSelector = makeSelectorFromSchemaMap(schema.getTransparentElements());
  2317. const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
  2318. return filter$5(scope.querySelectorAll(transparentSelector), transparent => updateTransparent(blocksSelector, transparent));
  2319. };
  2320. const trimEdge = (el, leftSide) => {
  2321. var _a;
  2322. const childPropertyName = leftSide ? 'lastChild' : 'firstChild';
  2323. for (let child = el[childPropertyName]; child; child = child[childPropertyName]) {
  2324. if (isEmpty$2(SugarElement.fromDom(child))) {
  2325. (_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
  2326. return;
  2327. }
  2328. }
  2329. };
  2330. const split$2 = (parentElm, splitElm) => {
  2331. const range = document.createRange();
  2332. const parentNode = parentElm.parentNode;
  2333. if (parentNode) {
  2334. range.setStartBefore(parentElm);
  2335. range.setEndBefore(splitElm);
  2336. const beforeFragment = range.extractContents();
  2337. trimEdge(beforeFragment, true);
  2338. range.setStartAfter(splitElm);
  2339. range.setEndAfter(parentElm);
  2340. const afterFragment = range.extractContents();
  2341. trimEdge(afterFragment, false);
  2342. if (!isEmpty$2(SugarElement.fromDom(beforeFragment))) {
  2343. parentNode.insertBefore(beforeFragment, parentElm);
  2344. }
  2345. if (!isEmpty$2(SugarElement.fromDom(splitElm))) {
  2346. parentNode.insertBefore(splitElm, parentElm);
  2347. }
  2348. if (!isEmpty$2(SugarElement.fromDom(afterFragment))) {
  2349. parentNode.insertBefore(afterFragment, parentElm);
  2350. }
  2351. parentNode.removeChild(parentElm);
  2352. }
  2353. };
  2354. const splitInvalidChildren = (schema, scope, transparentBlocks) => {
  2355. const blocksElements = schema.getBlockElements();
  2356. const rootNode = SugarElement.fromDom(scope);
  2357. const isBlock = el => name(el) in blocksElements;
  2358. const isRoot = el => eq(el, rootNode);
  2359. each$e(fromDom$1(transparentBlocks), transparentBlock => {
  2360. ancestor$3(transparentBlock, isBlock, isRoot).each(parentBlock => {
  2361. const invalidChildren = children(transparentBlock, el => isBlock(el) && !schema.isValidChild(name(parentBlock), name(el)));
  2362. if (invalidChildren.length > 0) {
  2363. const stateScope = parentElement(parentBlock);
  2364. each$e(invalidChildren, child => {
  2365. ancestor$3(child, isBlock, isRoot).each(parentBlock => {
  2366. split$2(parentBlock.dom, child.dom);
  2367. });
  2368. });
  2369. stateScope.each(scope => updateBlockStateOnChildren(schema, scope.dom));
  2370. }
  2371. });
  2372. });
  2373. };
  2374. const updateChildren = (schema, scope) => {
  2375. const transparentBlocks = updateBlockStateOnChildren(schema, scope);
  2376. splitInvalidChildren(schema, scope, transparentBlocks);
  2377. };
  2378. const updateElement = (schema, target) => {
  2379. if (isTransparentElement(schema, target)) {
  2380. const blocksSelector = makeSelectorFromSchemaMap(schema.getBlockElements());
  2381. updateTransparent(blocksSelector, target);
  2382. }
  2383. };
  2384. const updateCaret = (schema, root, caretParent) => {
  2385. const isRoot = el => eq(el, SugarElement.fromDom(root));
  2386. const parents = parents$1(SugarElement.fromDom(caretParent), isRoot);
  2387. get$b(parents, parents.length - 2).filter(isElement$7).fold(() => updateChildren(schema, root), scope => updateChildren(schema, scope.dom));
  2388. };
  2389. const hasBlockAttr = el => el.hasAttribute(transparentBlockAttr);
  2390. const isTransparentElementName = (schema, name) => has$2(schema.getTransparentElements(), name);
  2391. const isTransparentElement = (schema, node) => isElement$6(node) && isTransparentElementName(schema, node.nodeName);
  2392. const isTransparentBlock = (schema, node) => isTransparentElement(schema, node) && hasBlockAttr(node);
  2393. const isTransparentAstBlock = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isString(node.attr(transparentBlockAttr));
  2394. const isTransparentAstInline = (schema, node) => node.type === 1 && isTransparentElementName(schema, node.name) && isUndefined(node.attr(transparentBlockAttr));
  2395. const browser = detect$2().browser;
  2396. const firstElement = nodes => find$2(nodes, isElement$7);
  2397. const getTableCaptionDeltaY = elm => {
  2398. if (browser.isFirefox() && name(elm) === 'table') {
  2399. return firstElement(children$1(elm)).filter(elm => {
  2400. return name(elm) === 'caption';
  2401. }).bind(caption => {
  2402. return firstElement(nextSiblings(caption)).map(body => {
  2403. const bodyTop = body.dom.offsetTop;
  2404. const captionTop = caption.dom.offsetTop;
  2405. const captionHeight = caption.dom.offsetHeight;
  2406. return bodyTop <= captionTop ? -captionHeight : 0;
  2407. });
  2408. }).getOr(0);
  2409. } else {
  2410. return 0;
  2411. }
  2412. };
  2413. const hasChild = (elm, child) => elm.children && contains$2(elm.children, child);
  2414. const getPos = (body, elm, rootElm) => {
  2415. let x = 0, y = 0;
  2416. const doc = body.ownerDocument;
  2417. rootElm = rootElm ? rootElm : body;
  2418. if (elm) {
  2419. if (rootElm === body && elm.getBoundingClientRect && get$7(SugarElement.fromDom(body), 'position') === 'static') {
  2420. const pos = elm.getBoundingClientRect();
  2421. x = pos.left + (doc.documentElement.scrollLeft || body.scrollLeft) - doc.documentElement.clientLeft;
  2422. y = pos.top + (doc.documentElement.scrollTop || body.scrollTop) - doc.documentElement.clientTop;
  2423. return {
  2424. x,
  2425. y
  2426. };
  2427. }
  2428. let offsetParent = elm;
  2429. while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
  2430. const castOffsetParent = offsetParent;
  2431. x += castOffsetParent.offsetLeft || 0;
  2432. y += castOffsetParent.offsetTop || 0;
  2433. offsetParent = castOffsetParent.offsetParent;
  2434. }
  2435. offsetParent = elm.parentNode;
  2436. while (offsetParent && offsetParent !== rootElm && offsetParent.nodeType && !hasChild(offsetParent, rootElm)) {
  2437. x -= offsetParent.scrollLeft || 0;
  2438. y -= offsetParent.scrollTop || 0;
  2439. offsetParent = offsetParent.parentNode;
  2440. }
  2441. y += getTableCaptionDeltaY(SugarElement.fromDom(elm));
  2442. }
  2443. return {
  2444. x,
  2445. y
  2446. };
  2447. };
  2448. const StyleSheetLoader = (documentOrShadowRoot, settings = {}) => {
  2449. let idCount = 0;
  2450. const loadedStates = {};
  2451. const edos = SugarElement.fromDom(documentOrShadowRoot);
  2452. const doc = documentOrOwner(edos);
  2453. const maxLoadTime = settings.maxLoadTime || 5000;
  2454. const _setReferrerPolicy = referrerPolicy => {
  2455. settings.referrerPolicy = referrerPolicy;
  2456. };
  2457. const _setContentCssCors = contentCssCors => {
  2458. settings.contentCssCors = contentCssCors;
  2459. };
  2460. const addStyle = element => {
  2461. append$1(getStyleContainer(edos), element);
  2462. };
  2463. const removeStyle = id => {
  2464. const styleContainer = getStyleContainer(edos);
  2465. descendant(styleContainer, '#' + id).each(remove$6);
  2466. };
  2467. const getOrCreateState = url => get$a(loadedStates, url).getOrThunk(() => ({
  2468. id: 'mce-u' + idCount++,
  2469. passed: [],
  2470. failed: [],
  2471. count: 0
  2472. }));
  2473. const load = url => new Promise((success, failure) => {
  2474. let link;
  2475. const urlWithSuffix = Tools._addCacheSuffix(url);
  2476. const state = getOrCreateState(urlWithSuffix);
  2477. loadedStates[urlWithSuffix] = state;
  2478. state.count++;
  2479. const resolve = (callbacks, status) => {
  2480. each$e(callbacks, call);
  2481. state.status = status;
  2482. state.passed = [];
  2483. state.failed = [];
  2484. if (link) {
  2485. link.onload = null;
  2486. link.onerror = null;
  2487. link = null;
  2488. }
  2489. };
  2490. const passed = () => resolve(state.passed, 2);
  2491. const failed = () => resolve(state.failed, 3);
  2492. const wait = (testCallback, waitCallback) => {
  2493. if (!testCallback()) {
  2494. if (Date.now() - startTime < maxLoadTime) {
  2495. setTimeout(waitCallback);
  2496. } else {
  2497. failed();
  2498. }
  2499. }
  2500. };
  2501. const waitForWebKitLinkLoaded = () => {
  2502. wait(() => {
  2503. const styleSheets = documentOrShadowRoot.styleSheets;
  2504. let i = styleSheets.length;
  2505. while (i--) {
  2506. const styleSheet = styleSheets[i];
  2507. const owner = styleSheet.ownerNode;
  2508. if (owner && link && owner.id === link.id) {
  2509. passed();
  2510. return true;
  2511. }
  2512. }
  2513. return false;
  2514. }, waitForWebKitLinkLoaded);
  2515. };
  2516. if (success) {
  2517. state.passed.push(success);
  2518. }
  2519. if (failure) {
  2520. state.failed.push(failure);
  2521. }
  2522. if (state.status === 1) {
  2523. return;
  2524. }
  2525. if (state.status === 2) {
  2526. passed();
  2527. return;
  2528. }
  2529. if (state.status === 3) {
  2530. failed();
  2531. return;
  2532. }
  2533. state.status = 1;
  2534. const linkElem = SugarElement.fromTag('link', doc.dom);
  2535. setAll$1(linkElem, {
  2536. rel: 'stylesheet',
  2537. type: 'text/css',
  2538. id: state.id
  2539. });
  2540. const startTime = Date.now();
  2541. if (settings.contentCssCors) {
  2542. set$2(linkElem, 'crossOrigin', 'anonymous');
  2543. }
  2544. if (settings.referrerPolicy) {
  2545. set$2(linkElem, 'referrerpolicy', settings.referrerPolicy);
  2546. }
  2547. link = linkElem.dom;
  2548. link.onload = waitForWebKitLinkLoaded;
  2549. link.onerror = failed;
  2550. addStyle(linkElem);
  2551. set$2(linkElem, 'href', urlWithSuffix);
  2552. });
  2553. const loadAll = urls => {
  2554. const loadedUrls = Promise.allSettled(map$3(urls, url => load(url).then(constant(url))));
  2555. return loadedUrls.then(results => {
  2556. const parts = partition$2(results, r => r.status === 'fulfilled');
  2557. if (parts.fail.length > 0) {
  2558. return Promise.reject(map$3(parts.fail, result => result.reason));
  2559. } else {
  2560. return map$3(parts.pass, result => result.value);
  2561. }
  2562. });
  2563. };
  2564. const unload = url => {
  2565. const urlWithSuffix = Tools._addCacheSuffix(url);
  2566. get$a(loadedStates, urlWithSuffix).each(state => {
  2567. const count = --state.count;
  2568. if (count === 0) {
  2569. delete loadedStates[urlWithSuffix];
  2570. removeStyle(state.id);
  2571. }
  2572. });
  2573. };
  2574. const unloadAll = urls => {
  2575. each$e(urls, url => {
  2576. unload(url);
  2577. });
  2578. };
  2579. return {
  2580. load,
  2581. loadAll,
  2582. unload,
  2583. unloadAll,
  2584. _setReferrerPolicy,
  2585. _setContentCssCors
  2586. };
  2587. };
  2588. const create$d = () => {
  2589. const map = new WeakMap();
  2590. const forElement = (referenceElement, settings) => {
  2591. const root = getRootNode(referenceElement);
  2592. const rootDom = root.dom;
  2593. return Optional.from(map.get(rootDom)).getOrThunk(() => {
  2594. const sl = StyleSheetLoader(rootDom, settings);
  2595. map.set(rootDom, sl);
  2596. return sl;
  2597. });
  2598. };
  2599. return { forElement };
  2600. };
  2601. const instance = create$d();
  2602. const isSpan = node => node.nodeName.toLowerCase() === 'span';
  2603. const isInlineContent = (node, root) => isNonNullable(node) && (isContent$1(node, root) || isInline$1(SugarElement.fromDom(node)));
  2604. const surroundedByInlineContent = (node, root) => {
  2605. const prev = new DomTreeWalker(node, root).prev(false);
  2606. const next = new DomTreeWalker(node, root).next(false);
  2607. const prevIsInline = isUndefined(prev) || isInlineContent(prev, root);
  2608. const nextIsInline = isUndefined(next) || isInlineContent(next, root);
  2609. return prevIsInline && nextIsInline;
  2610. };
  2611. const isBookmarkNode$2 = node => isSpan(node) && node.getAttribute('data-mce-type') === 'bookmark';
  2612. const isKeepTextNode = (node, root) => isText$a(node) && node.data.length > 0 && surroundedByInlineContent(node, root);
  2613. const isKeepElement = node => isElement$6(node) ? node.childNodes.length > 0 : false;
  2614. const isDocument = node => isDocumentFragment(node) || isDocument$1(node);
  2615. const trimNode = (dom, node, root) => {
  2616. var _a;
  2617. const rootNode = root || node;
  2618. if (isElement$6(node) && isBookmarkNode$2(node)) {
  2619. return node;
  2620. }
  2621. const children = node.childNodes;
  2622. for (let i = children.length - 1; i >= 0; i--) {
  2623. trimNode(dom, children[i], rootNode);
  2624. }
  2625. if (isElement$6(node)) {
  2626. const currentChildren = node.childNodes;
  2627. if (currentChildren.length === 1 && isBookmarkNode$2(currentChildren[0])) {
  2628. (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(currentChildren[0], node);
  2629. }
  2630. }
  2631. if (!isDocument(node) && !isContent$1(node, rootNode) && !isKeepElement(node) && !isKeepTextNode(node, rootNode)) {
  2632. dom.remove(node);
  2633. }
  2634. return node;
  2635. };
  2636. const makeMap$3 = Tools.makeMap;
  2637. const attrsCharsRegExp = /[&<>\"\u0060\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
  2638. const textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
  2639. const rawCharsRegExp = /[<>&\"\']/g;
  2640. const entityRegExp = /&#([a-z0-9]+);?|&([a-z0-9]+);/gi;
  2641. const asciiMap = {
  2642. 128: '\u20AC',
  2643. 130: '\u201A',
  2644. 131: '\u0192',
  2645. 132: '\u201E',
  2646. 133: '\u2026',
  2647. 134: '\u2020',
  2648. 135: '\u2021',
  2649. 136: '\u02c6',
  2650. 137: '\u2030',
  2651. 138: '\u0160',
  2652. 139: '\u2039',
  2653. 140: '\u0152',
  2654. 142: '\u017d',
  2655. 145: '\u2018',
  2656. 146: '\u2019',
  2657. 147: '\u201C',
  2658. 148: '\u201D',
  2659. 149: '\u2022',
  2660. 150: '\u2013',
  2661. 151: '\u2014',
  2662. 152: '\u02DC',
  2663. 153: '\u2122',
  2664. 154: '\u0161',
  2665. 155: '\u203A',
  2666. 156: '\u0153',
  2667. 158: '\u017e',
  2668. 159: '\u0178'
  2669. };
  2670. const baseEntities = {
  2671. '"': '&quot;',
  2672. '\'': '&#39;',
  2673. '<': '&lt;',
  2674. '>': '&gt;',
  2675. '&': '&amp;',
  2676. '`': '&#96;'
  2677. };
  2678. const reverseEntities = {
  2679. '&lt;': '<',
  2680. '&gt;': '>',
  2681. '&amp;': '&',
  2682. '&quot;': '"',
  2683. '&apos;': `'`
  2684. };
  2685. const nativeDecode = text => {
  2686. const elm = SugarElement.fromTag('div').dom;
  2687. elm.innerHTML = text;
  2688. return elm.textContent || elm.innerText || text;
  2689. };
  2690. const buildEntitiesLookup = (items, radix) => {
  2691. const lookup = {};
  2692. if (items) {
  2693. const itemList = items.split(',');
  2694. radix = radix || 10;
  2695. for (let i = 0; i < itemList.length; i += 2) {
  2696. const chr = String.fromCharCode(parseInt(itemList[i], radix));
  2697. if (!baseEntities[chr]) {
  2698. const entity = '&' + itemList[i + 1] + ';';
  2699. lookup[chr] = entity;
  2700. lookup[entity] = chr;
  2701. }
  2702. }
  2703. return lookup;
  2704. } else {
  2705. return undefined;
  2706. }
  2707. };
  2708. const namedEntities = buildEntitiesLookup('50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' + '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' + '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' + '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' + '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' + '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' + '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' + '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' + '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' + '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' + 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' + 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' + 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' + 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' + 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' + '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' + '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' + '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' + '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' + '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' + 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' + 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' + 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' + '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' + '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
  2709. const encodeRaw = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
  2710. return baseEntities[chr] || chr;
  2711. });
  2712. const encodeAllRaw = text => ('' + text).replace(rawCharsRegExp, chr => {
  2713. return baseEntities[chr] || chr;
  2714. });
  2715. const encodeNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
  2716. if (chr.length > 1) {
  2717. return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
  2718. }
  2719. return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
  2720. });
  2721. const encodeNamed = (text, attr, entities) => {
  2722. const resolveEntities = entities || namedEntities;
  2723. return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
  2724. return baseEntities[chr] || resolveEntities[chr] || chr;
  2725. });
  2726. };
  2727. const getEncodeFunc = (name, entities) => {
  2728. const entitiesMap = buildEntitiesLookup(entities) || namedEntities;
  2729. const encodeNamedAndNumeric = (text, attr) => text.replace(attr ? attrsCharsRegExp : textCharsRegExp, chr => {
  2730. if (baseEntities[chr] !== undefined) {
  2731. return baseEntities[chr];
  2732. }
  2733. if (entitiesMap[chr] !== undefined) {
  2734. return entitiesMap[chr];
  2735. }
  2736. if (chr.length > 1) {
  2737. return '&#' + ((chr.charCodeAt(0) - 55296) * 1024 + (chr.charCodeAt(1) - 56320) + 65536) + ';';
  2738. }
  2739. return '&#' + chr.charCodeAt(0) + ';';
  2740. });
  2741. const encodeCustomNamed = (text, attr) => {
  2742. return encodeNamed(text, attr, entitiesMap);
  2743. };
  2744. const nameMap = makeMap$3(name.replace(/\+/g, ','));
  2745. if (nameMap.named && nameMap.numeric) {
  2746. return encodeNamedAndNumeric;
  2747. }
  2748. if (nameMap.named) {
  2749. if (entities) {
  2750. return encodeCustomNamed;
  2751. }
  2752. return encodeNamed;
  2753. }
  2754. if (nameMap.numeric) {
  2755. return encodeNumeric;
  2756. }
  2757. return encodeRaw;
  2758. };
  2759. const decode = text => text.replace(entityRegExp, (all, numeric) => {
  2760. if (numeric) {
  2761. if (numeric.charAt(0).toLowerCase() === 'x') {
  2762. numeric = parseInt(numeric.substr(1), 16);
  2763. } else {
  2764. numeric = parseInt(numeric, 10);
  2765. }
  2766. if (numeric > 65535) {
  2767. numeric -= 65536;
  2768. return String.fromCharCode(55296 + (numeric >> 10), 56320 + (numeric & 1023));
  2769. }
  2770. return asciiMap[numeric] || String.fromCharCode(numeric);
  2771. }
  2772. return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
  2773. });
  2774. const Entities = {
  2775. encodeRaw,
  2776. encodeAllRaw,
  2777. encodeNumeric,
  2778. encodeNamed,
  2779. getEncodeFunc,
  2780. decode
  2781. };
  2782. const lookupCache = {};
  2783. const mapCache = {};
  2784. const dummyObj = {};
  2785. const makeMap$2 = Tools.makeMap, each$b = Tools.each, extend$2 = Tools.extend, explode$2 = Tools.explode, inArray = Tools.inArray;
  2786. const split$1 = (items, delim) => {
  2787. items = Tools.trim(items);
  2788. return items ? items.split(delim || ' ') : [];
  2789. };
  2790. const createMap = (defaultValue, extendWith = {}) => {
  2791. const value = makeMap$2(defaultValue, ' ', makeMap$2(defaultValue.toUpperCase(), ' '));
  2792. return extend$2(value, extendWith);
  2793. };
  2794. const getTextRootBlockElements = schema => createMap('td th li dt dd figcaption caption details summary', schema.getTextBlockElements());
  2795. const compileSchema = type => {
  2796. const schema = {};
  2797. let globalAttributes, blockContent;
  2798. let phrasingContent, flowContent;
  2799. const add = (name, attributes = '', children = '') => {
  2800. const childNames = split$1(children);
  2801. const names = split$1(name);
  2802. let ni = names.length;
  2803. while (ni--) {
  2804. const attributesOrder = split$1([
  2805. globalAttributes,
  2806. attributes
  2807. ].join(' '));
  2808. schema[names[ni]] = {
  2809. attributes: mapToObject(attributesOrder, () => ({})),
  2810. attributesOrder,
  2811. children: mapToObject(childNames, constant(dummyObj))
  2812. };
  2813. }
  2814. };
  2815. const addAttrs = (name, attributes) => {
  2816. const names = split$1(name);
  2817. const attrs = split$1(attributes);
  2818. let ni = names.length;
  2819. while (ni--) {
  2820. const schemaItem = schema[names[ni]];
  2821. for (let i = 0, l = attrs.length; i < l; i++) {
  2822. schemaItem.attributes[attrs[i]] = {};
  2823. schemaItem.attributesOrder.push(attrs[i]);
  2824. }
  2825. }
  2826. };
  2827. if (lookupCache[type]) {
  2828. return lookupCache[type];
  2829. }
  2830. globalAttributes = 'id accesskey class dir lang style tabindex title role';
  2831. blockContent = 'address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul';
  2832. phrasingContent = 'a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd ' + 'label map noscript object q s samp script select small span strong sub sup ' + 'textarea u var #text #comment';
  2833. if (type !== 'html4') {
  2834. const transparentContent = 'a ins del canvas map';
  2835. globalAttributes += ' contenteditable contextmenu draggable dropzone ' + 'hidden spellcheck translate';
  2836. blockContent += ' article aside details dialog figure main header footer hgroup section nav ' + transparentContent;
  2837. phrasingContent += ' audio canvas command datalist mark meter output picture ' + 'progress time wbr video ruby bdi keygen';
  2838. }
  2839. if (type !== 'html5-strict') {
  2840. globalAttributes += ' xml:lang';
  2841. const html4PhrasingContent = 'acronym applet basefont big font strike tt';
  2842. phrasingContent = [
  2843. phrasingContent,
  2844. html4PhrasingContent
  2845. ].join(' ');
  2846. each$b(split$1(html4PhrasingContent), name => {
  2847. add(name, '', phrasingContent);
  2848. });
  2849. const html4BlockContent = 'center dir isindex noframes';
  2850. blockContent = [
  2851. blockContent,
  2852. html4BlockContent
  2853. ].join(' ');
  2854. flowContent = [
  2855. blockContent,
  2856. phrasingContent
  2857. ].join(' ');
  2858. each$b(split$1(html4BlockContent), name => {
  2859. add(name, '', flowContent);
  2860. });
  2861. }
  2862. flowContent = flowContent || [
  2863. blockContent,
  2864. phrasingContent
  2865. ].join(' ');
  2866. add('html', 'manifest', 'head body');
  2867. add('head', '', 'base command link meta noscript script style title');
  2868. add('title hr noscript br');
  2869. add('base', 'href target');
  2870. add('link', 'href rel media hreflang type sizes hreflang');
  2871. add('meta', 'name http-equiv content charset');
  2872. add('style', 'media type scoped');
  2873. add('script', 'src async defer type charset');
  2874. add('body', 'onafterprint onbeforeprint onbeforeunload onblur onerror onfocus ' + 'onhashchange onload onmessage onoffline ononline onpagehide onpageshow ' + 'onpopstate onresize onscroll onstorage onunload', flowContent);
  2875. add('address dt dd div caption', '', flowContent);
  2876. add('h1 h2 h3 h4 h5 h6 pre p abbr code var samp kbd sub sup i b u bdo span legend em strong small s cite dfn', '', phrasingContent);
  2877. add('blockquote', 'cite', flowContent);
  2878. add('ol', 'reversed start type', 'li');
  2879. add('ul', '', 'li');
  2880. add('li', 'value', flowContent);
  2881. add('dl', '', 'dt dd');
  2882. add('a', 'href target rel media hreflang type', flowContent);
  2883. add('q', 'cite', phrasingContent);
  2884. add('ins del', 'cite datetime', flowContent);
  2885. add('img', 'src sizes srcset alt usemap ismap width height');
  2886. add('iframe', 'src name width height', flowContent);
  2887. add('embed', 'src type width height');
  2888. add('object', 'data type typemustmatch name usemap form width height', [
  2889. flowContent,
  2890. 'param'
  2891. ].join(' '));
  2892. add('param', 'name value');
  2893. add('map', 'name', [
  2894. flowContent,
  2895. 'area'
  2896. ].join(' '));
  2897. add('area', 'alt coords shape href target rel media hreflang type');
  2898. add('table', 'border', 'caption colgroup thead tfoot tbody tr' + (type === 'html4' ? ' col' : ''));
  2899. add('colgroup', 'span', 'col');
  2900. add('col', 'span');
  2901. add('tbody thead tfoot', '', 'tr');
  2902. add('tr', '', 'td th');
  2903. add('td', 'colspan rowspan headers', flowContent);
  2904. add('th', 'colspan rowspan headers scope abbr', flowContent);
  2905. add('form', 'accept-charset action autocomplete enctype method name novalidate target', flowContent);
  2906. add('fieldset', 'disabled form name', [
  2907. flowContent,
  2908. 'legend'
  2909. ].join(' '));
  2910. add('label', 'form for', phrasingContent);
  2911. add('input', 'accept alt autocomplete checked dirname disabled form formaction formenctype formmethod formnovalidate ' + 'formtarget height list max maxlength min multiple name pattern readonly required size src step type value width');
  2912. add('button', 'disabled form formaction formenctype formmethod formnovalidate formtarget name type value', type === 'html4' ? flowContent : phrasingContent);
  2913. add('select', 'disabled form multiple name required size', 'option optgroup');
  2914. add('optgroup', 'disabled label', 'option');
  2915. add('option', 'disabled label selected value');
  2916. add('textarea', 'cols dirname disabled form maxlength name readonly required rows wrap');
  2917. add('menu', 'type label', [
  2918. flowContent,
  2919. 'li'
  2920. ].join(' '));
  2921. add('noscript', '', flowContent);
  2922. if (type !== 'html4') {
  2923. add('wbr');
  2924. add('ruby', '', [
  2925. phrasingContent,
  2926. 'rt rp'
  2927. ].join(' '));
  2928. add('figcaption', '', flowContent);
  2929. add('mark rt rp summary bdi', '', phrasingContent);
  2930. add('canvas', 'width height', flowContent);
  2931. add('video', 'src crossorigin poster preload autoplay mediagroup loop ' + 'muted controls width height buffered', [
  2932. flowContent,
  2933. 'track source'
  2934. ].join(' '));
  2935. add('audio', 'src crossorigin preload autoplay mediagroup loop muted controls ' + 'buffered volume', [
  2936. flowContent,
  2937. 'track source'
  2938. ].join(' '));
  2939. add('picture', '', 'img source');
  2940. add('source', 'src srcset type media sizes');
  2941. add('track', 'kind src srclang label default');
  2942. add('datalist', '', [
  2943. phrasingContent,
  2944. 'option'
  2945. ].join(' '));
  2946. add('article section nav aside main header footer', '', flowContent);
  2947. add('hgroup', '', 'h1 h2 h3 h4 h5 h6');
  2948. add('figure', '', [
  2949. flowContent,
  2950. 'figcaption'
  2951. ].join(' '));
  2952. add('time', 'datetime', phrasingContent);
  2953. add('dialog', 'open', flowContent);
  2954. add('command', 'type label icon disabled checked radiogroup command');
  2955. add('output', 'for form name', phrasingContent);
  2956. add('progress', 'value max', phrasingContent);
  2957. add('meter', 'value min max low high optimum', phrasingContent);
  2958. add('details', 'open', [
  2959. flowContent,
  2960. 'summary'
  2961. ].join(' '));
  2962. add('keygen', 'autofocus challenge disabled form keytype name');
  2963. }
  2964. if (type !== 'html5-strict') {
  2965. addAttrs('script', 'language xml:space');
  2966. addAttrs('style', 'xml:space');
  2967. addAttrs('object', 'declare classid code codebase codetype archive standby align border hspace vspace');
  2968. addAttrs('embed', 'align name hspace vspace');
  2969. addAttrs('param', 'valuetype type');
  2970. addAttrs('a', 'charset name rev shape coords');
  2971. addAttrs('br', 'clear');
  2972. addAttrs('applet', 'codebase archive code object alt name width height align hspace vspace');
  2973. addAttrs('img', 'name longdesc align border hspace vspace');
  2974. addAttrs('iframe', 'longdesc frameborder marginwidth marginheight scrolling align');
  2975. addAttrs('font basefont', 'size color face');
  2976. addAttrs('input', 'usemap align');
  2977. addAttrs('select');
  2978. addAttrs('textarea');
  2979. addAttrs('h1 h2 h3 h4 h5 h6 div p legend caption', 'align');
  2980. addAttrs('ul', 'type compact');
  2981. addAttrs('li', 'type');
  2982. addAttrs('ol dl menu dir', 'compact');
  2983. addAttrs('pre', 'width xml:space');
  2984. addAttrs('hr', 'align noshade size width');
  2985. addAttrs('isindex', 'prompt');
  2986. addAttrs('table', 'summary width frame rules cellspacing cellpadding align bgcolor');
  2987. addAttrs('col', 'width align char charoff valign');
  2988. addAttrs('colgroup', 'width align char charoff valign');
  2989. addAttrs('thead', 'align char charoff valign');
  2990. addAttrs('tr', 'align char charoff valign bgcolor');
  2991. addAttrs('th', 'axis align char charoff valign nowrap bgcolor width height');
  2992. addAttrs('form', 'accept');
  2993. addAttrs('td', 'abbr axis scope align char charoff valign nowrap bgcolor width height');
  2994. addAttrs('tfoot', 'align char charoff valign');
  2995. addAttrs('tbody', 'align char charoff valign');
  2996. addAttrs('area', 'nohref');
  2997. addAttrs('body', 'background bgcolor text link vlink alink');
  2998. }
  2999. if (type !== 'html4') {
  3000. addAttrs('input button select textarea', 'autofocus');
  3001. addAttrs('input textarea', 'placeholder');
  3002. addAttrs('a', 'download');
  3003. addAttrs('link script img', 'crossorigin');
  3004. addAttrs('img', 'loading');
  3005. addAttrs('iframe', 'sandbox seamless allow allowfullscreen loading');
  3006. }
  3007. if (type !== 'html4') {
  3008. each$e([
  3009. schema.video,
  3010. schema.audio
  3011. ], item => {
  3012. delete item.children.audio;
  3013. delete item.children.video;
  3014. });
  3015. }
  3016. each$b(split$1('a form meter progress dfn'), name => {
  3017. if (schema[name]) {
  3018. delete schema[name].children[name];
  3019. }
  3020. });
  3021. delete schema.caption.children.table;
  3022. delete schema.script;
  3023. lookupCache[type] = schema;
  3024. return schema;
  3025. };
  3026. const compileElementMap = (value, mode) => {
  3027. if (value) {
  3028. const styles = {};
  3029. if (isString(value)) {
  3030. value = { '*': value };
  3031. }
  3032. each$b(value, (value, key) => {
  3033. styles[key] = styles[key.toUpperCase()] = mode === 'map' ? makeMap$2(value, /[, ]/) : explode$2(value, /[, ]/);
  3034. });
  3035. return styles;
  3036. } else {
  3037. return undefined;
  3038. }
  3039. };
  3040. const Schema = (settings = {}) => {
  3041. var _a;
  3042. const elements = {};
  3043. const children = {};
  3044. let patternElements = [];
  3045. const customElementsMap = {};
  3046. const specialElements = {};
  3047. const createLookupTable = (option, defaultValue, extendWith) => {
  3048. const value = settings[option];
  3049. if (!value) {
  3050. let newValue = mapCache[option];
  3051. if (!newValue) {
  3052. newValue = createMap(defaultValue, extendWith);
  3053. mapCache[option] = newValue;
  3054. }
  3055. return newValue;
  3056. } else {
  3057. return makeMap$2(value, /[, ]/, makeMap$2(value.toUpperCase(), /[, ]/));
  3058. }
  3059. };
  3060. const schemaType = (_a = settings.schema) !== null && _a !== void 0 ? _a : 'html5';
  3061. const schemaItems = compileSchema(schemaType);
  3062. if (settings.verify_html === false) {
  3063. settings.valid_elements = '*[*]';
  3064. }
  3065. const validStyles = compileElementMap(settings.valid_styles);
  3066. const invalidStyles = compileElementMap(settings.invalid_styles, 'map');
  3067. const validClasses = compileElementMap(settings.valid_classes, 'map');
  3068. const whitespaceElementsMap = createLookupTable('whitespace_elements', 'pre script noscript style textarea video audio iframe object code');
  3069. const selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
  3070. const voidElementsMap = createLookupTable('void_elements', 'area base basefont br col frame hr img input isindex link ' + 'meta param embed source wbr track');
  3071. const boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize ' + 'noshade nowrap readonly selected autoplay loop controls allowfullscreen');
  3072. const nonEmptyOrMoveCaretBeforeOnEnter = 'td th iframe video audio object script code';
  3073. const nonEmptyElementsMap = createLookupTable('non_empty_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' pre', voidElementsMap);
  3074. const moveCaretBeforeOnEnterElementsMap = createLookupTable('move_caret_before_on_enter_elements', nonEmptyOrMoveCaretBeforeOnEnter + ' table', voidElementsMap);
  3075. const textBlockElementsMap = createLookupTable('text_block_elements', 'h1 h2 h3 h4 h5 h6 p div address pre form ' + 'blockquote center dir fieldset header footer article section hgroup aside main nav figure');
  3076. const blockElementsMap = createLookupTable('block_elements', 'hr table tbody thead tfoot ' + 'th tr td li ol ul caption dl dt dd noscript menu isindex option ' + 'datalist select optgroup figcaption details summary', textBlockElementsMap);
  3077. const textInlineElementsMap = createLookupTable('text_inline_elements', 'span strong b em i font s strike u var cite ' + 'dfn code mark q sup sub samp');
  3078. const transparentElementsMap = createLookupTable('transparent_elements', 'a ins del canvas map');
  3079. each$b('script noscript iframe noframes noembed title style textarea xmp plaintext'.split(' '), name => {
  3080. specialElements[name] = new RegExp('</' + name + '[^>]*>', 'gi');
  3081. });
  3082. const patternToRegExp = str => new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
  3083. const addValidElements = validElements => {
  3084. const elementRuleRegExp = /^([#+\-])?([^\[!\/]+)(?:\/([^\[!]+))?(?:(!?)\[([^\]]+)])?$/;
  3085. const attrRuleRegExp = /^([!\-])?(\w+[\\:]:\w+|[^=~<]+)?(?:([=~<])(.*))?$/;
  3086. const hasPatternsRegExp = /[*?+]/;
  3087. if (validElements) {
  3088. const validElementsArr = split$1(validElements, ',');
  3089. let globalAttributes;
  3090. let globalAttributesOrder;
  3091. if (elements['@']) {
  3092. globalAttributes = elements['@'].attributes;
  3093. globalAttributesOrder = elements['@'].attributesOrder;
  3094. }
  3095. for (let ei = 0, el = validElementsArr.length; ei < el; ei++) {
  3096. let matches = elementRuleRegExp.exec(validElementsArr[ei]);
  3097. if (matches) {
  3098. const prefix = matches[1];
  3099. const elementName = matches[2];
  3100. const outputName = matches[3];
  3101. const attrData = matches[5];
  3102. const attributes = {};
  3103. const attributesOrder = [];
  3104. const element = {
  3105. attributes,
  3106. attributesOrder
  3107. };
  3108. if (prefix === '#') {
  3109. element.paddEmpty = true;
  3110. }
  3111. if (prefix === '-') {
  3112. element.removeEmpty = true;
  3113. }
  3114. if (matches[4] === '!') {
  3115. element.removeEmptyAttrs = true;
  3116. }
  3117. if (globalAttributes) {
  3118. each$d(globalAttributes, (value, key) => {
  3119. attributes[key] = value;
  3120. });
  3121. if (globalAttributesOrder) {
  3122. attributesOrder.push(...globalAttributesOrder);
  3123. }
  3124. }
  3125. if (attrData) {
  3126. const attrDatas = split$1(attrData, '|');
  3127. for (let ai = 0, al = attrDatas.length; ai < al; ai++) {
  3128. matches = attrRuleRegExp.exec(attrDatas[ai]);
  3129. if (matches) {
  3130. const attr = {};
  3131. const attrType = matches[1];
  3132. const attrName = matches[2].replace(/[\\:]:/g, ':');
  3133. const attrPrefix = matches[3];
  3134. const value = matches[4];
  3135. if (attrType === '!') {
  3136. element.attributesRequired = element.attributesRequired || [];
  3137. element.attributesRequired.push(attrName);
  3138. attr.required = true;
  3139. }
  3140. if (attrType === '-') {
  3141. delete attributes[attrName];
  3142. attributesOrder.splice(inArray(attributesOrder, attrName), 1);
  3143. continue;
  3144. }
  3145. if (attrPrefix) {
  3146. if (attrPrefix === '=') {
  3147. element.attributesDefault = element.attributesDefault || [];
  3148. element.attributesDefault.push({
  3149. name: attrName,
  3150. value
  3151. });
  3152. attr.defaultValue = value;
  3153. }
  3154. if (attrPrefix === '~') {
  3155. element.attributesForced = element.attributesForced || [];
  3156. element.attributesForced.push({
  3157. name: attrName,
  3158. value
  3159. });
  3160. attr.forcedValue = value;
  3161. }
  3162. if (attrPrefix === '<') {
  3163. attr.validValues = makeMap$2(value, '?');
  3164. }
  3165. }
  3166. if (hasPatternsRegExp.test(attrName)) {
  3167. const attrPattern = attr;
  3168. element.attributePatterns = element.attributePatterns || [];
  3169. attrPattern.pattern = patternToRegExp(attrName);
  3170. element.attributePatterns.push(attrPattern);
  3171. } else {
  3172. if (!attributes[attrName]) {
  3173. attributesOrder.push(attrName);
  3174. }
  3175. attributes[attrName] = attr;
  3176. }
  3177. }
  3178. }
  3179. }
  3180. if (!globalAttributes && elementName === '@') {
  3181. globalAttributes = attributes;
  3182. globalAttributesOrder = attributesOrder;
  3183. }
  3184. if (outputName) {
  3185. element.outputName = elementName;
  3186. elements[outputName] = element;
  3187. }
  3188. if (hasPatternsRegExp.test(elementName)) {
  3189. const patternElement = element;
  3190. patternElement.pattern = patternToRegExp(elementName);
  3191. patternElements.push(patternElement);
  3192. } else {
  3193. elements[elementName] = element;
  3194. }
  3195. }
  3196. }
  3197. }
  3198. };
  3199. const setValidElements = validElements => {
  3200. patternElements = [];
  3201. each$e(keys(elements), name => {
  3202. delete elements[name];
  3203. });
  3204. addValidElements(validElements);
  3205. each$b(schemaItems, (element, name) => {
  3206. children[name] = element.children;
  3207. });
  3208. };
  3209. const addCustomElements = customElements => {
  3210. const customElementRegExp = /^(~)?(.+)$/;
  3211. if (customElements) {
  3212. delete mapCache.text_block_elements;
  3213. delete mapCache.block_elements;
  3214. each$b(split$1(customElements, ','), rule => {
  3215. const matches = customElementRegExp.exec(rule);
  3216. if (matches) {
  3217. const inline = matches[1] === '~';
  3218. const cloneName = inline ? 'span' : 'div';
  3219. const name = matches[2];
  3220. children[name] = children[cloneName];
  3221. customElementsMap[name] = cloneName;
  3222. nonEmptyElementsMap[name.toUpperCase()] = {};
  3223. nonEmptyElementsMap[name] = {};
  3224. if (!inline) {
  3225. blockElementsMap[name.toUpperCase()] = {};
  3226. blockElementsMap[name] = {};
  3227. }
  3228. if (!elements[name]) {
  3229. let customRule = elements[cloneName];
  3230. customRule = extend$2({}, customRule);
  3231. delete customRule.removeEmptyAttrs;
  3232. delete customRule.removeEmpty;
  3233. elements[name] = customRule;
  3234. }
  3235. each$b(children, (element, elmName) => {
  3236. if (element[cloneName]) {
  3237. children[elmName] = element = extend$2({}, children[elmName]);
  3238. element[name] = element[cloneName];
  3239. }
  3240. });
  3241. }
  3242. });
  3243. }
  3244. };
  3245. const addValidChildren = validChildren => {
  3246. const childRuleRegExp = /^([+\-]?)([A-Za-z0-9_\-.\u00b7\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u037d\u037f-\u1fff\u200c-\u200d\u203f-\u2040\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff\uf900-\ufdcf\ufdf0-\ufffd]+)\[([^\]]+)]$/;
  3247. delete lookupCache[schemaType];
  3248. if (validChildren) {
  3249. each$b(split$1(validChildren, ','), rule => {
  3250. const matches = childRuleRegExp.exec(rule);
  3251. if (matches) {
  3252. const prefix = matches[1];
  3253. let parent;
  3254. if (prefix) {
  3255. parent = children[matches[2]];
  3256. } else {
  3257. parent = children[matches[2]] = { '#comment': {} };
  3258. }
  3259. parent = children[matches[2]];
  3260. each$b(split$1(matches[3], '|'), child => {
  3261. if (prefix === '-') {
  3262. delete parent[child];
  3263. } else {
  3264. parent[child] = {};
  3265. }
  3266. });
  3267. }
  3268. });
  3269. }
  3270. };
  3271. const getElementRule = name => {
  3272. const element = elements[name];
  3273. if (element) {
  3274. return element;
  3275. }
  3276. let i = patternElements.length;
  3277. while (i--) {
  3278. const patternElement = patternElements[i];
  3279. if (patternElement.pattern.test(name)) {
  3280. return patternElement;
  3281. }
  3282. }
  3283. return undefined;
  3284. };
  3285. if (!settings.valid_elements) {
  3286. each$b(schemaItems, (element, name) => {
  3287. elements[name] = {
  3288. attributes: element.attributes,
  3289. attributesOrder: element.attributesOrder
  3290. };
  3291. children[name] = element.children;
  3292. });
  3293. each$b(split$1('strong/b em/i'), item => {
  3294. const items = split$1(item, '/');
  3295. elements[items[1]].outputName = items[0];
  3296. });
  3297. each$b(textInlineElementsMap, (_val, name) => {
  3298. if (elements[name]) {
  3299. if (settings.padd_empty_block_inline_children) {
  3300. elements[name].paddInEmptyBlock = true;
  3301. }
  3302. elements[name].removeEmpty = true;
  3303. }
  3304. });
  3305. each$b(split$1('ol ul blockquote a table tbody'), name => {
  3306. if (elements[name]) {
  3307. elements[name].removeEmpty = true;
  3308. }
  3309. });
  3310. each$b(split$1('p h1 h2 h3 h4 h5 h6 th td pre div address caption li'), name => {
  3311. elements[name].paddEmpty = true;
  3312. });
  3313. each$b(split$1('span'), name => {
  3314. elements[name].removeEmptyAttrs = true;
  3315. });
  3316. } else {
  3317. setValidElements(settings.valid_elements);
  3318. }
  3319. addCustomElements(settings.custom_elements);
  3320. addValidChildren(settings.valid_children);
  3321. addValidElements(settings.extended_valid_elements);
  3322. addValidChildren('+ol[ul|ol],+ul[ul|ol]');
  3323. each$b({
  3324. dd: 'dl',
  3325. dt: 'dl',
  3326. li: 'ul ol',
  3327. td: 'tr',
  3328. th: 'tr',
  3329. tr: 'tbody thead tfoot',
  3330. tbody: 'table',
  3331. thead: 'table',
  3332. tfoot: 'table',
  3333. legend: 'fieldset',
  3334. area: 'map',
  3335. param: 'video audio object'
  3336. }, (parents, item) => {
  3337. if (elements[item]) {
  3338. elements[item].parentsRequired = split$1(parents);
  3339. }
  3340. });
  3341. if (settings.invalid_elements) {
  3342. each$b(explode$2(settings.invalid_elements), item => {
  3343. if (elements[item]) {
  3344. delete elements[item];
  3345. }
  3346. });
  3347. }
  3348. if (!getElementRule('span')) {
  3349. addValidElements('span[!data-mce-type|*]');
  3350. }
  3351. const getValidStyles = constant(validStyles);
  3352. const getInvalidStyles = constant(invalidStyles);
  3353. const getValidClasses = constant(validClasses);
  3354. const getBoolAttrs = constant(boolAttrMap);
  3355. const getBlockElements = constant(blockElementsMap);
  3356. const getTextBlockElements = constant(textBlockElementsMap);
  3357. const getTextInlineElements = constant(textInlineElementsMap);
  3358. const getVoidElements = constant(Object.seal(voidElementsMap));
  3359. const getSelfClosingElements = constant(selfClosingElementsMap);
  3360. const getNonEmptyElements = constant(nonEmptyElementsMap);
  3361. const getMoveCaretBeforeOnEnterElements = constant(moveCaretBeforeOnEnterElementsMap);
  3362. const getWhitespaceElements = constant(whitespaceElementsMap);
  3363. const getTransparentElements = constant(transparentElementsMap);
  3364. const getSpecialElements = constant(Object.seal(specialElements));
  3365. const isValidChild = (name, child) => {
  3366. const parent = children[name.toLowerCase()];
  3367. return !!(parent && parent[child.toLowerCase()]);
  3368. };
  3369. const isValid = (name, attr) => {
  3370. const rule = getElementRule(name);
  3371. if (rule) {
  3372. if (attr) {
  3373. if (rule.attributes[attr]) {
  3374. return true;
  3375. }
  3376. const attrPatterns = rule.attributePatterns;
  3377. if (attrPatterns) {
  3378. let i = attrPatterns.length;
  3379. while (i--) {
  3380. if (attrPatterns[i].pattern.test(attr)) {
  3381. return true;
  3382. }
  3383. }
  3384. }
  3385. } else {
  3386. return true;
  3387. }
  3388. }
  3389. return false;
  3390. };
  3391. const getCustomElements = constant(customElementsMap);
  3392. return {
  3393. type: schemaType,
  3394. children,
  3395. elements,
  3396. getValidStyles,
  3397. getValidClasses,
  3398. getBlockElements,
  3399. getInvalidStyles,
  3400. getVoidElements,
  3401. getTextBlockElements,
  3402. getTextInlineElements,
  3403. getBoolAttrs,
  3404. getElementRule,
  3405. getSelfClosingElements,
  3406. getNonEmptyElements,
  3407. getMoveCaretBeforeOnEnterElements,
  3408. getWhitespaceElements,
  3409. getTransparentElements,
  3410. getSpecialElements,
  3411. isValidChild,
  3412. isValid,
  3413. getCustomElements,
  3414. addValidElements,
  3415. setValidElements,
  3416. addCustomElements,
  3417. addValidChildren
  3418. };
  3419. };
  3420. const Styles = (settings = {}, schema) => {
  3421. const urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi;
  3422. const styleRegExp = /\s*([^:]+):\s*([^;]+);?/g;
  3423. const trimRightRegExp = /\s+$/;
  3424. const encodingLookup = {};
  3425. let validStyles;
  3426. let invalidStyles;
  3427. const invisibleChar = zeroWidth;
  3428. if (schema) {
  3429. validStyles = schema.getValidStyles();
  3430. invalidStyles = schema.getInvalidStyles();
  3431. }
  3432. const encodingItems = (`\\" \\' \\; \\: ; : ` + invisibleChar).split(' ');
  3433. for (let i = 0; i < encodingItems.length; i++) {
  3434. encodingLookup[encodingItems[i]] = invisibleChar + i;
  3435. encodingLookup[invisibleChar + i] = encodingItems[i];
  3436. }
  3437. const self = {
  3438. parse: css => {
  3439. const styles = {};
  3440. let isEncoded = false;
  3441. const urlConverter = settings.url_converter;
  3442. const urlConverterScope = settings.url_converter_scope || self;
  3443. const compress = (prefix, suffix, noJoin) => {
  3444. const top = styles[prefix + '-top' + suffix];
  3445. if (!top) {
  3446. return;
  3447. }
  3448. const right = styles[prefix + '-right' + suffix];
  3449. if (!right) {
  3450. return;
  3451. }
  3452. const bottom = styles[prefix + '-bottom' + suffix];
  3453. if (!bottom) {
  3454. return;
  3455. }
  3456. const left = styles[prefix + '-left' + suffix];
  3457. if (!left) {
  3458. return;
  3459. }
  3460. const box = [
  3461. top,
  3462. right,
  3463. bottom,
  3464. left
  3465. ];
  3466. let i = box.length - 1;
  3467. while (i--) {
  3468. if (box[i] !== box[i + 1]) {
  3469. break;
  3470. }
  3471. }
  3472. if (i > -1 && noJoin) {
  3473. return;
  3474. }
  3475. styles[prefix + suffix] = i === -1 ? box[0] : box.join(' ');
  3476. delete styles[prefix + '-top' + suffix];
  3477. delete styles[prefix + '-right' + suffix];
  3478. delete styles[prefix + '-bottom' + suffix];
  3479. delete styles[prefix + '-left' + suffix];
  3480. };
  3481. const canCompress = key => {
  3482. const value = styles[key];
  3483. if (!value) {
  3484. return;
  3485. }
  3486. const values = value.split(' ');
  3487. let i = values.length;
  3488. while (i--) {
  3489. if (values[i] !== values[0]) {
  3490. return false;
  3491. }
  3492. }
  3493. styles[key] = values[0];
  3494. return true;
  3495. };
  3496. const compress2 = (target, a, b, c) => {
  3497. if (!canCompress(a)) {
  3498. return;
  3499. }
  3500. if (!canCompress(b)) {
  3501. return;
  3502. }
  3503. if (!canCompress(c)) {
  3504. return;
  3505. }
  3506. styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
  3507. delete styles[a];
  3508. delete styles[b];
  3509. delete styles[c];
  3510. };
  3511. const encode = str => {
  3512. isEncoded = true;
  3513. return encodingLookup[str];
  3514. };
  3515. const decode = (str, keepSlashes) => {
  3516. if (isEncoded) {
  3517. str = str.replace(/\uFEFF[0-9]/g, str => {
  3518. return encodingLookup[str];
  3519. });
  3520. }
  3521. if (!keepSlashes) {
  3522. str = str.replace(/\\([\'\";:])/g, '$1');
  3523. }
  3524. return str;
  3525. };
  3526. const decodeSingleHexSequence = escSeq => {
  3527. return String.fromCharCode(parseInt(escSeq.slice(1), 16));
  3528. };
  3529. const decodeHexSequences = value => {
  3530. return value.replace(/\\[0-9a-f]+/gi, decodeSingleHexSequence);
  3531. };
  3532. const processUrl = (match, url, url2, url3, str, str2) => {
  3533. str = str || str2;
  3534. if (str) {
  3535. str = decode(str);
  3536. return `'` + str.replace(/\'/g, `\\'`) + `'`;
  3537. }
  3538. url = decode(url || url2 || url3 || '');
  3539. if (!settings.allow_script_urls) {
  3540. const scriptUrl = url.replace(/[\s\r\n]+/g, '');
  3541. if (/(java|vb)script:/i.test(scriptUrl)) {
  3542. return '';
  3543. }
  3544. if (!settings.allow_svg_data_urls && /^data:image\/svg/i.test(scriptUrl)) {
  3545. return '';
  3546. }
  3547. }
  3548. if (urlConverter) {
  3549. url = urlConverter.call(urlConverterScope, url, 'style');
  3550. }
  3551. return `url('` + url.replace(/\'/g, `\\'`) + `')`;
  3552. };
  3553. if (css) {
  3554. css = css.replace(/[\u0000-\u001F]/g, '');
  3555. css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, str => {
  3556. return str.replace(/[;:]/g, encode);
  3557. });
  3558. let matches;
  3559. while (matches = styleRegExp.exec(css)) {
  3560. styleRegExp.lastIndex = matches.index + matches[0].length;
  3561. let name = matches[1].replace(trimRightRegExp, '').toLowerCase();
  3562. let value = matches[2].replace(trimRightRegExp, '');
  3563. if (name && value) {
  3564. name = decodeHexSequences(name);
  3565. value = decodeHexSequences(value);
  3566. if (name.indexOf(invisibleChar) !== -1 || name.indexOf('"') !== -1) {
  3567. continue;
  3568. }
  3569. if (!settings.allow_script_urls && (name === 'behavior' || /expression\s*\(|\/\*|\*\//.test(value))) {
  3570. continue;
  3571. }
  3572. if (name === 'font-weight' && value === '700') {
  3573. value = 'bold';
  3574. } else if (name === 'color' || name === 'background-color') {
  3575. value = value.toLowerCase();
  3576. }
  3577. value = value.replace(urlOrStrRegExp, processUrl);
  3578. styles[name] = isEncoded ? decode(value, true) : value;
  3579. }
  3580. }
  3581. compress('border', '', true);
  3582. compress('border', '-width');
  3583. compress('border', '-color');
  3584. compress('border', '-style');
  3585. compress('padding', '');
  3586. compress('margin', '');
  3587. compress2('border', 'border-width', 'border-style', 'border-color');
  3588. if (styles.border === 'medium none') {
  3589. delete styles.border;
  3590. }
  3591. if (styles['border-image'] === 'none') {
  3592. delete styles['border-image'];
  3593. }
  3594. }
  3595. return styles;
  3596. },
  3597. serialize: (styles, elementName) => {
  3598. let css = '';
  3599. const serializeStyles = (elemName, validStyleList) => {
  3600. const styleList = validStyleList[elemName];
  3601. if (styleList) {
  3602. for (let i = 0, l = styleList.length; i < l; i++) {
  3603. const name = styleList[i];
  3604. const value = styles[name];
  3605. if (value) {
  3606. css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
  3607. }
  3608. }
  3609. }
  3610. };
  3611. const isValid = (name, elemName) => {
  3612. if (!invalidStyles || !elemName) {
  3613. return true;
  3614. }
  3615. let styleMap = invalidStyles['*'];
  3616. if (styleMap && styleMap[name]) {
  3617. return false;
  3618. }
  3619. styleMap = invalidStyles[elemName];
  3620. return !(styleMap && styleMap[name]);
  3621. };
  3622. if (elementName && validStyles) {
  3623. serializeStyles('*', validStyles);
  3624. serializeStyles(elementName, validStyles);
  3625. } else {
  3626. each$d(styles, (value, name) => {
  3627. if (value && isValid(name, elementName)) {
  3628. css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
  3629. }
  3630. });
  3631. }
  3632. return css;
  3633. }
  3634. };
  3635. return self;
  3636. };
  3637. const deprecated = {
  3638. keyLocation: true,
  3639. layerX: true,
  3640. layerY: true,
  3641. returnValue: true,
  3642. webkitMovementX: true,
  3643. webkitMovementY: true,
  3644. keyIdentifier: true,
  3645. mozPressure: true
  3646. };
  3647. const isNativeEvent = event => event instanceof Event || isFunction(event.initEvent);
  3648. const hasIsDefaultPrevented = event => event.isDefaultPrevented === always || event.isDefaultPrevented === never;
  3649. const needsNormalizing = event => isNullable(event.preventDefault) || isNativeEvent(event);
  3650. const clone$3 = (originalEvent, data) => {
  3651. const event = data !== null && data !== void 0 ? data : {};
  3652. for (const name in originalEvent) {
  3653. if (!has$2(deprecated, name)) {
  3654. event[name] = originalEvent[name];
  3655. }
  3656. }
  3657. if (isNonNullable(originalEvent.composedPath)) {
  3658. event.composedPath = () => originalEvent.composedPath();
  3659. }
  3660. return event;
  3661. };
  3662. const normalize$3 = (type, originalEvent, fallbackTarget, data) => {
  3663. var _a;
  3664. const event = clone$3(originalEvent, data);
  3665. event.type = type;
  3666. if (isNullable(event.target)) {
  3667. event.target = (_a = event.srcElement) !== null && _a !== void 0 ? _a : fallbackTarget;
  3668. }
  3669. if (needsNormalizing(originalEvent)) {
  3670. event.preventDefault = () => {
  3671. event.defaultPrevented = true;
  3672. event.isDefaultPrevented = always;
  3673. if (isFunction(originalEvent.preventDefault)) {
  3674. originalEvent.preventDefault();
  3675. }
  3676. };
  3677. event.stopPropagation = () => {
  3678. event.cancelBubble = true;
  3679. event.isPropagationStopped = always;
  3680. if (isFunction(originalEvent.stopPropagation)) {
  3681. originalEvent.stopPropagation();
  3682. }
  3683. };
  3684. event.stopImmediatePropagation = () => {
  3685. event.isImmediatePropagationStopped = always;
  3686. event.stopPropagation();
  3687. };
  3688. if (!hasIsDefaultPrevented(event)) {
  3689. event.isDefaultPrevented = event.defaultPrevented === true ? always : never;
  3690. event.isPropagationStopped = event.cancelBubble === true ? always : never;
  3691. event.isImmediatePropagationStopped = never;
  3692. }
  3693. }
  3694. return event;
  3695. };
  3696. const eventExpandoPrefix = 'mce-data-';
  3697. const mouseEventRe = /^(?:mouse|contextmenu)|click/;
  3698. const addEvent = (target, name, callback, capture) => {
  3699. target.addEventListener(name, callback, capture || false);
  3700. };
  3701. const removeEvent = (target, name, callback, capture) => {
  3702. target.removeEventListener(name, callback, capture || false);
  3703. };
  3704. const isMouseEvent = event => isNonNullable(event) && mouseEventRe.test(event.type);
  3705. const fix = (originalEvent, data) => {
  3706. const event = normalize$3(originalEvent.type, originalEvent, document, data);
  3707. if (isMouseEvent(originalEvent) && isUndefined(originalEvent.pageX) && !isUndefined(originalEvent.clientX)) {
  3708. const eventDoc = event.target.ownerDocument || document;
  3709. const doc = eventDoc.documentElement;
  3710. const body = eventDoc.body;
  3711. const mouseEvent = event;
  3712. mouseEvent.pageX = originalEvent.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
  3713. mouseEvent.pageY = originalEvent.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
  3714. }
  3715. return event;
  3716. };
  3717. const bindOnReady = (win, callback, eventUtils) => {
  3718. const doc = win.document, event = { type: 'ready' };
  3719. if (eventUtils.domLoaded) {
  3720. callback(event);
  3721. return;
  3722. }
  3723. const isDocReady = () => {
  3724. return doc.readyState === 'complete' || doc.readyState === 'interactive' && doc.body;
  3725. };
  3726. const readyHandler = () => {
  3727. removeEvent(win, 'DOMContentLoaded', readyHandler);
  3728. removeEvent(win, 'load', readyHandler);
  3729. if (!eventUtils.domLoaded) {
  3730. eventUtils.domLoaded = true;
  3731. callback(event);
  3732. }
  3733. win = null;
  3734. };
  3735. if (isDocReady()) {
  3736. readyHandler();
  3737. } else {
  3738. addEvent(win, 'DOMContentLoaded', readyHandler);
  3739. }
  3740. if (!eventUtils.domLoaded) {
  3741. addEvent(win, 'load', readyHandler);
  3742. }
  3743. };
  3744. class EventUtils {
  3745. constructor() {
  3746. this.domLoaded = false;
  3747. this.events = {};
  3748. this.count = 1;
  3749. this.expando = eventExpandoPrefix + (+new Date()).toString(32);
  3750. this.hasFocusIn = 'onfocusin' in document.documentElement;
  3751. this.count = 1;
  3752. }
  3753. bind(target, names, callback, scope) {
  3754. const self = this;
  3755. let callbackList;
  3756. const win = window;
  3757. const defaultNativeHandler = evt => {
  3758. self.executeHandlers(fix(evt || win.event), id);
  3759. };
  3760. if (!target || isText$a(target) || isComment(target)) {
  3761. return callback;
  3762. }
  3763. let id;
  3764. if (!target[self.expando]) {
  3765. id = self.count++;
  3766. target[self.expando] = id;
  3767. self.events[id] = {};
  3768. } else {
  3769. id = target[self.expando];
  3770. }
  3771. scope = scope || target;
  3772. const namesList = names.split(' ');
  3773. let i = namesList.length;
  3774. while (i--) {
  3775. let name = namesList[i];
  3776. let nativeHandler = defaultNativeHandler;
  3777. let capture = false;
  3778. let fakeName = false;
  3779. if (name === 'DOMContentLoaded') {
  3780. name = 'ready';
  3781. }
  3782. if (self.domLoaded && name === 'ready' && target.readyState === 'complete') {
  3783. callback.call(scope, fix({ type: name }));
  3784. continue;
  3785. }
  3786. if (!self.hasFocusIn && (name === 'focusin' || name === 'focusout')) {
  3787. capture = true;
  3788. fakeName = name === 'focusin' ? 'focus' : 'blur';
  3789. nativeHandler = evt => {
  3790. const event = fix(evt || win.event);
  3791. event.type = event.type === 'focus' ? 'focusin' : 'focusout';
  3792. self.executeHandlers(event, id);
  3793. };
  3794. }
  3795. callbackList = self.events[id][name];
  3796. if (!callbackList) {
  3797. self.events[id][name] = callbackList = [{
  3798. func: callback,
  3799. scope
  3800. }];
  3801. callbackList.fakeName = fakeName;
  3802. callbackList.capture = capture;
  3803. callbackList.nativeHandler = nativeHandler;
  3804. if (name === 'ready') {
  3805. bindOnReady(target, nativeHandler, self);
  3806. } else {
  3807. addEvent(target, fakeName || name, nativeHandler, capture);
  3808. }
  3809. } else {
  3810. if (name === 'ready' && self.domLoaded) {
  3811. callback(fix({ type: name }));
  3812. } else {
  3813. callbackList.push({
  3814. func: callback,
  3815. scope
  3816. });
  3817. }
  3818. }
  3819. }
  3820. target = callbackList = null;
  3821. return callback;
  3822. }
  3823. unbind(target, names, callback) {
  3824. if (!target || isText$a(target) || isComment(target)) {
  3825. return this;
  3826. }
  3827. const id = target[this.expando];
  3828. if (id) {
  3829. let eventMap = this.events[id];
  3830. if (names) {
  3831. const namesList = names.split(' ');
  3832. let i = namesList.length;
  3833. while (i--) {
  3834. const name = namesList[i];
  3835. const callbackList = eventMap[name];
  3836. if (callbackList) {
  3837. if (callback) {
  3838. let ci = callbackList.length;
  3839. while (ci--) {
  3840. if (callbackList[ci].func === callback) {
  3841. const nativeHandler = callbackList.nativeHandler;
  3842. const fakeName = callbackList.fakeName, capture = callbackList.capture;
  3843. const newCallbackList = callbackList.slice(0, ci).concat(callbackList.slice(ci + 1));
  3844. newCallbackList.nativeHandler = nativeHandler;
  3845. newCallbackList.fakeName = fakeName;
  3846. newCallbackList.capture = capture;
  3847. eventMap[name] = newCallbackList;
  3848. }
  3849. }
  3850. }
  3851. if (!callback || callbackList.length === 0) {
  3852. delete eventMap[name];
  3853. removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
  3854. }
  3855. }
  3856. }
  3857. } else {
  3858. each$d(eventMap, (callbackList, name) => {
  3859. removeEvent(target, callbackList.fakeName || name, callbackList.nativeHandler, callbackList.capture);
  3860. });
  3861. eventMap = {};
  3862. }
  3863. for (const name in eventMap) {
  3864. if (has$2(eventMap, name)) {
  3865. return this;
  3866. }
  3867. }
  3868. delete this.events[id];
  3869. try {
  3870. delete target[this.expando];
  3871. } catch (ex) {
  3872. target[this.expando] = null;
  3873. }
  3874. }
  3875. return this;
  3876. }
  3877. fire(target, name, args) {
  3878. return this.dispatch(target, name, args);
  3879. }
  3880. dispatch(target, name, args) {
  3881. if (!target || isText$a(target) || isComment(target)) {
  3882. return this;
  3883. }
  3884. const event = fix({
  3885. type: name,
  3886. target
  3887. }, args);
  3888. do {
  3889. const id = target[this.expando];
  3890. if (id) {
  3891. this.executeHandlers(event, id);
  3892. }
  3893. target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
  3894. } while (target && !event.isPropagationStopped());
  3895. return this;
  3896. }
  3897. clean(target) {
  3898. if (!target || isText$a(target) || isComment(target)) {
  3899. return this;
  3900. }
  3901. if (target[this.expando]) {
  3902. this.unbind(target);
  3903. }
  3904. if (!target.getElementsByTagName) {
  3905. target = target.document;
  3906. }
  3907. if (target && target.getElementsByTagName) {
  3908. this.unbind(target);
  3909. const children = target.getElementsByTagName('*');
  3910. let i = children.length;
  3911. while (i--) {
  3912. target = children[i];
  3913. if (target[this.expando]) {
  3914. this.unbind(target);
  3915. }
  3916. }
  3917. }
  3918. return this;
  3919. }
  3920. destroy() {
  3921. this.events = {};
  3922. }
  3923. cancel(e) {
  3924. if (e) {
  3925. e.preventDefault();
  3926. e.stopImmediatePropagation();
  3927. }
  3928. return false;
  3929. }
  3930. executeHandlers(evt, id) {
  3931. const container = this.events[id];
  3932. const callbackList = container && container[evt.type];
  3933. if (callbackList) {
  3934. for (let i = 0, l = callbackList.length; i < l; i++) {
  3935. const callback = callbackList[i];
  3936. if (callback && callback.func.call(callback.scope, evt) === false) {
  3937. evt.preventDefault();
  3938. }
  3939. if (evt.isImmediatePropagationStopped()) {
  3940. return;
  3941. }
  3942. }
  3943. }
  3944. }
  3945. }
  3946. EventUtils.Event = new EventUtils();
  3947. const each$a = Tools.each;
  3948. const grep = Tools.grep;
  3949. const internalStyleName = 'data-mce-style';
  3950. const numericalCssMap = Tools.makeMap('fill-opacity font-weight line-height opacity orphans widows z-index zoom', ' ');
  3951. const legacySetAttribute = (elm, name, value) => {
  3952. if (isNullable(value) || value === '') {
  3953. remove$b(elm, name);
  3954. } else {
  3955. set$2(elm, name, value);
  3956. }
  3957. };
  3958. const camelCaseToHyphens = name => name.replace(/[A-Z]/g, v => '-' + v.toLowerCase());
  3959. const findNodeIndex = (node, normalized) => {
  3960. let idx = 0;
  3961. if (node) {
  3962. for (let lastNodeType = node.nodeType, tempNode = node.previousSibling; tempNode; tempNode = tempNode.previousSibling) {
  3963. const nodeType = tempNode.nodeType;
  3964. if (normalized && isText$a(tempNode)) {
  3965. if (nodeType === lastNodeType || !tempNode.data.length) {
  3966. continue;
  3967. }
  3968. }
  3969. idx++;
  3970. lastNodeType = nodeType;
  3971. }
  3972. }
  3973. return idx;
  3974. };
  3975. const updateInternalStyleAttr = (styles, elm) => {
  3976. const rawValue = get$9(elm, 'style');
  3977. const value = styles.serialize(styles.parse(rawValue), name(elm));
  3978. legacySetAttribute(elm, internalStyleName, value);
  3979. };
  3980. const convertStyleToString = (cssValue, cssName) => {
  3981. if (isNumber(cssValue)) {
  3982. return has$2(numericalCssMap, cssName) ? cssValue + '' : cssValue + 'px';
  3983. } else {
  3984. return cssValue;
  3985. }
  3986. };
  3987. const applyStyle$1 = ($elm, cssName, cssValue) => {
  3988. const normalizedName = camelCaseToHyphens(cssName);
  3989. if (isNullable(cssValue) || cssValue === '') {
  3990. remove$7($elm, normalizedName);
  3991. } else {
  3992. set$1($elm, normalizedName, convertStyleToString(cssValue, normalizedName));
  3993. }
  3994. };
  3995. const setupAttrHooks = (styles, settings, getContext) => {
  3996. const keepValues = settings.keep_values;
  3997. const keepUrlHook = {
  3998. set: (elm, value, name) => {
  3999. const sugarElm = SugarElement.fromDom(elm);
  4000. if (isFunction(settings.url_converter) && isNonNullable(value)) {
  4001. value = settings.url_converter.call(settings.url_converter_scope || getContext(), String(value), name, elm);
  4002. }
  4003. const internalName = 'data-mce-' + name;
  4004. legacySetAttribute(sugarElm, internalName, value);
  4005. legacySetAttribute(sugarElm, name, value);
  4006. },
  4007. get: (elm, name) => {
  4008. const sugarElm = SugarElement.fromDom(elm);
  4009. return get$9(sugarElm, 'data-mce-' + name) || get$9(sugarElm, name);
  4010. }
  4011. };
  4012. const attrHooks = {
  4013. style: {
  4014. set: (elm, value) => {
  4015. const sugarElm = SugarElement.fromDom(elm);
  4016. if (keepValues) {
  4017. legacySetAttribute(sugarElm, internalStyleName, value);
  4018. }
  4019. remove$b(sugarElm, 'style');
  4020. if (isString(value)) {
  4021. setAll(sugarElm, styles.parse(value));
  4022. }
  4023. },
  4024. get: elm => {
  4025. const sugarElm = SugarElement.fromDom(elm);
  4026. const value = get$9(sugarElm, internalStyleName) || get$9(sugarElm, 'style');
  4027. return styles.serialize(styles.parse(value), name(sugarElm));
  4028. }
  4029. }
  4030. };
  4031. if (keepValues) {
  4032. attrHooks.href = attrHooks.src = keepUrlHook;
  4033. }
  4034. return attrHooks;
  4035. };
  4036. const DOMUtils = (doc, settings = {}) => {
  4037. const addedStyles = {};
  4038. const win = window;
  4039. const files = {};
  4040. let counter = 0;
  4041. const stdMode = true;
  4042. const boxModel = true;
  4043. const styleSheetLoader = instance.forElement(SugarElement.fromDom(doc), {
  4044. contentCssCors: settings.contentCssCors,
  4045. referrerPolicy: settings.referrerPolicy
  4046. });
  4047. const boundEvents = [];
  4048. const schema = settings.schema ? settings.schema : Schema({});
  4049. const styles = Styles({
  4050. url_converter: settings.url_converter,
  4051. url_converter_scope: settings.url_converter_scope
  4052. }, settings.schema);
  4053. const events = settings.ownEvents ? new EventUtils() : EventUtils.Event;
  4054. const blockElementsMap = schema.getBlockElements();
  4055. const isBlock = node => {
  4056. if (isString(node)) {
  4057. return has$2(blockElementsMap, node);
  4058. } else {
  4059. return isElement$6(node) && (has$2(blockElementsMap, node.nodeName) || isTransparentBlock(schema, node));
  4060. }
  4061. };
  4062. const get = elm => elm && doc && isString(elm) ? doc.getElementById(elm) : elm;
  4063. const _get = elm => {
  4064. const value = get(elm);
  4065. return isNonNullable(value) ? SugarElement.fromDom(value) : null;
  4066. };
  4067. const getAttrib = (elm, name, defaultVal = '') => {
  4068. let value;
  4069. const $elm = _get(elm);
  4070. if (isNonNullable($elm) && isElement$7($elm)) {
  4071. const hook = attrHooks[name];
  4072. if (hook && hook.get) {
  4073. value = hook.get($elm.dom, name);
  4074. } else {
  4075. value = get$9($elm, name);
  4076. }
  4077. }
  4078. return isNonNullable(value) ? value : defaultVal;
  4079. };
  4080. const getAttribs = elm => {
  4081. const node = get(elm);
  4082. return isNullable(node) ? [] : node.attributes;
  4083. };
  4084. const setAttrib = (elm, name, value) => {
  4085. run(elm, e => {
  4086. if (isElement$6(e)) {
  4087. const $elm = SugarElement.fromDom(e);
  4088. const val = value === '' ? null : value;
  4089. const originalValue = get$9($elm, name);
  4090. const hook = attrHooks[name];
  4091. if (hook && hook.set) {
  4092. hook.set($elm.dom, val, name);
  4093. } else {
  4094. legacySetAttribute($elm, name, val);
  4095. }
  4096. if (originalValue !== val && settings.onSetAttrib) {
  4097. settings.onSetAttrib({
  4098. attrElm: $elm.dom,
  4099. attrName: name,
  4100. attrValue: val
  4101. });
  4102. }
  4103. }
  4104. });
  4105. };
  4106. const clone = (node, deep) => {
  4107. return node.cloneNode(deep);
  4108. };
  4109. const getRoot = () => settings.root_element || doc.body;
  4110. const getViewPort = argWin => {
  4111. const vp = getBounds(argWin);
  4112. return {
  4113. x: vp.x,
  4114. y: vp.y,
  4115. w: vp.width,
  4116. h: vp.height
  4117. };
  4118. };
  4119. const getPos$1 = (elm, rootElm) => getPos(doc.body, get(elm), rootElm);
  4120. const setStyle = (elm, name, value) => {
  4121. run(elm, e => {
  4122. const $elm = SugarElement.fromDom(e);
  4123. applyStyle$1($elm, name, value);
  4124. if (settings.update_styles) {
  4125. updateInternalStyleAttr(styles, $elm);
  4126. }
  4127. });
  4128. };
  4129. const setStyles = (elm, stylesArg) => {
  4130. run(elm, e => {
  4131. const $elm = SugarElement.fromDom(e);
  4132. each$d(stylesArg, (v, n) => {
  4133. applyStyle$1($elm, n, v);
  4134. });
  4135. if (settings.update_styles) {
  4136. updateInternalStyleAttr(styles, $elm);
  4137. }
  4138. });
  4139. };
  4140. const getStyle = (elm, name, computed) => {
  4141. const $elm = get(elm);
  4142. if (isNullable($elm) || !isElement$6($elm)) {
  4143. return undefined;
  4144. }
  4145. if (computed) {
  4146. return get$7(SugarElement.fromDom($elm), camelCaseToHyphens(name));
  4147. } else {
  4148. name = name.replace(/-(\D)/g, (a, b) => b.toUpperCase());
  4149. if (name === 'float') {
  4150. name = 'cssFloat';
  4151. }
  4152. return $elm.style ? $elm.style[name] : undefined;
  4153. }
  4154. };
  4155. const getSize = elm => {
  4156. const $elm = get(elm);
  4157. if (!$elm) {
  4158. return {
  4159. w: 0,
  4160. h: 0
  4161. };
  4162. }
  4163. let w = getStyle($elm, 'width');
  4164. let h = getStyle($elm, 'height');
  4165. if (!w || w.indexOf('px') === -1) {
  4166. w = '0';
  4167. }
  4168. if (!h || h.indexOf('px') === -1) {
  4169. h = '0';
  4170. }
  4171. return {
  4172. w: parseInt(w, 10) || $elm.offsetWidth || $elm.clientWidth,
  4173. h: parseInt(h, 10) || $elm.offsetHeight || $elm.clientHeight
  4174. };
  4175. };
  4176. const getRect = elm => {
  4177. const $elm = get(elm);
  4178. const pos = getPos$1($elm);
  4179. const size = getSize($elm);
  4180. return {
  4181. x: pos.x,
  4182. y: pos.y,
  4183. w: size.w,
  4184. h: size.h
  4185. };
  4186. };
  4187. const is = (elm, selector) => {
  4188. if (!elm) {
  4189. return false;
  4190. }
  4191. const elms = isArray$1(elm) ? elm : [elm];
  4192. return exists(elms, e => {
  4193. return is$1(SugarElement.fromDom(e), selector);
  4194. });
  4195. };
  4196. const getParents = (elm, selector, root, collect) => {
  4197. const result = [];
  4198. let node = get(elm);
  4199. collect = collect === undefined;
  4200. const resolvedRoot = root || (getRoot().nodeName !== 'BODY' ? getRoot().parentNode : null);
  4201. if (isString(selector)) {
  4202. if (selector === '*') {
  4203. selector = isElement$6;
  4204. } else {
  4205. const selectorVal = selector;
  4206. selector = node => is(node, selectorVal);
  4207. }
  4208. }
  4209. while (node) {
  4210. if (node === resolvedRoot || isNullable(node.nodeType) || isDocument$1(node) || isDocumentFragment(node)) {
  4211. break;
  4212. }
  4213. if (!selector || selector(node)) {
  4214. if (collect) {
  4215. result.push(node);
  4216. } else {
  4217. return [node];
  4218. }
  4219. }
  4220. node = node.parentNode;
  4221. }
  4222. return collect ? result : null;
  4223. };
  4224. const getParent = (node, selector, root) => {
  4225. const parents = getParents(node, selector, root, false);
  4226. return parents && parents.length > 0 ? parents[0] : null;
  4227. };
  4228. const _findSib = (node, selector, name) => {
  4229. let func = selector;
  4230. if (node) {
  4231. if (isString(selector)) {
  4232. func = node => {
  4233. return is(node, selector);
  4234. };
  4235. }
  4236. for (let tempNode = node[name]; tempNode; tempNode = tempNode[name]) {
  4237. if (isFunction(func) && func(tempNode)) {
  4238. return tempNode;
  4239. }
  4240. }
  4241. }
  4242. return null;
  4243. };
  4244. const getNext = (node, selector) => _findSib(node, selector, 'nextSibling');
  4245. const getPrev = (node, selector) => _findSib(node, selector, 'previousSibling');
  4246. const isParentNode = node => isFunction(node.querySelectorAll);
  4247. const select = (selector, scope) => {
  4248. var _a, _b;
  4249. const elm = (_b = (_a = get(scope)) !== null && _a !== void 0 ? _a : settings.root_element) !== null && _b !== void 0 ? _b : doc;
  4250. return isParentNode(elm) ? from(elm.querySelectorAll(selector)) : [];
  4251. };
  4252. const run = function (elm, func, scope) {
  4253. const context = scope !== null && scope !== void 0 ? scope : this;
  4254. if (isArray$1(elm)) {
  4255. const result = [];
  4256. each$a(elm, (e, i) => {
  4257. const node = get(e);
  4258. if (node) {
  4259. result.push(func.call(context, node, i));
  4260. }
  4261. });
  4262. return result;
  4263. } else {
  4264. const node = get(elm);
  4265. return !node ? false : func.call(context, node);
  4266. }
  4267. };
  4268. const setAttribs = (elm, attrs) => {
  4269. run(elm, $elm => {
  4270. each$d(attrs, (value, name) => {
  4271. setAttrib($elm, name, value);
  4272. });
  4273. });
  4274. };
  4275. const setHTML = (elm, html) => {
  4276. run(elm, e => {
  4277. const $elm = SugarElement.fromDom(e);
  4278. set($elm, html);
  4279. });
  4280. };
  4281. const add = (parentElm, name, attrs, html, create) => run(parentElm, parentElm => {
  4282. const newElm = isString(name) ? doc.createElement(name) : name;
  4283. if (isNonNullable(attrs)) {
  4284. setAttribs(newElm, attrs);
  4285. }
  4286. if (html) {
  4287. if (!isString(html) && html.nodeType) {
  4288. newElm.appendChild(html);
  4289. } else if (isString(html)) {
  4290. setHTML(newElm, html);
  4291. }
  4292. }
  4293. return !create ? parentElm.appendChild(newElm) : newElm;
  4294. });
  4295. const create = (name, attrs, html) => add(doc.createElement(name), name, attrs, html, true);
  4296. const decode = Entities.decode;
  4297. const encode = Entities.encodeAllRaw;
  4298. const createHTML = (name, attrs, html = '') => {
  4299. let outHtml = '<' + name;
  4300. for (const key in attrs) {
  4301. if (hasNonNullableKey(attrs, key)) {
  4302. outHtml += ' ' + key + '="' + encode(attrs[key]) + '"';
  4303. }
  4304. }
  4305. if (isEmpty$3(html) && has$2(schema.getVoidElements(), name)) {
  4306. return outHtml + ' />';
  4307. } else {
  4308. return outHtml + '>' + html + '</' + name + '>';
  4309. }
  4310. };
  4311. const createFragment = html => {
  4312. const container = doc.createElement('div');
  4313. const frag = doc.createDocumentFragment();
  4314. frag.appendChild(container);
  4315. if (html) {
  4316. container.innerHTML = html;
  4317. }
  4318. let node;
  4319. while (node = container.firstChild) {
  4320. frag.appendChild(node);
  4321. }
  4322. frag.removeChild(container);
  4323. return frag;
  4324. };
  4325. const remove = (node, keepChildren) => {
  4326. return run(node, n => {
  4327. const $node = SugarElement.fromDom(n);
  4328. if (keepChildren) {
  4329. each$e(children$1($node), child => {
  4330. if (isText$b(child) && child.dom.length === 0) {
  4331. remove$6(child);
  4332. } else {
  4333. before$3($node, child);
  4334. }
  4335. });
  4336. }
  4337. remove$6($node);
  4338. return $node.dom;
  4339. });
  4340. };
  4341. const removeAllAttribs = e => run(e, e => {
  4342. const attrs = e.attributes;
  4343. for (let i = attrs.length - 1; i >= 0; i--) {
  4344. e.removeAttributeNode(attrs.item(i));
  4345. }
  4346. });
  4347. const parseStyle = cssText => styles.parse(cssText);
  4348. const serializeStyle = (stylesArg, name) => styles.serialize(stylesArg, name);
  4349. const addStyle = cssText => {
  4350. if (self !== DOMUtils.DOM && doc === document) {
  4351. if (addedStyles[cssText]) {
  4352. return;
  4353. }
  4354. addedStyles[cssText] = true;
  4355. }
  4356. let styleElm = doc.getElementById('mceDefaultStyles');
  4357. if (!styleElm) {
  4358. styleElm = doc.createElement('style');
  4359. styleElm.id = 'mceDefaultStyles';
  4360. styleElm.type = 'text/css';
  4361. const head = doc.head;
  4362. if (head.firstChild) {
  4363. head.insertBefore(styleElm, head.firstChild);
  4364. } else {
  4365. head.appendChild(styleElm);
  4366. }
  4367. }
  4368. if (styleElm.styleSheet) {
  4369. styleElm.styleSheet.cssText += cssText;
  4370. } else {
  4371. styleElm.appendChild(doc.createTextNode(cssText));
  4372. }
  4373. };
  4374. const loadCSS = urls => {
  4375. if (!urls) {
  4376. urls = '';
  4377. }
  4378. each$e(urls.split(','), url => {
  4379. files[url] = true;
  4380. styleSheetLoader.load(url).catch(noop);
  4381. });
  4382. };
  4383. const toggleClass = (elm, cls, state) => {
  4384. run(elm, e => {
  4385. if (isElement$6(e)) {
  4386. const $elm = SugarElement.fromDom(e);
  4387. const classes = cls.split(' ');
  4388. each$e(classes, c => {
  4389. if (isNonNullable(state)) {
  4390. const fn = state ? add$2 : remove$8;
  4391. fn($elm, c);
  4392. } else {
  4393. toggle$1($elm, c);
  4394. }
  4395. });
  4396. }
  4397. });
  4398. };
  4399. const addClass = (elm, cls) => {
  4400. toggleClass(elm, cls, true);
  4401. };
  4402. const removeClass = (elm, cls) => {
  4403. toggleClass(elm, cls, false);
  4404. };
  4405. const hasClass = (elm, cls) => {
  4406. const $elm = _get(elm);
  4407. const classes = cls.split(' ');
  4408. return isNonNullable($elm) && forall(classes, c => has($elm, c));
  4409. };
  4410. const show = elm => {
  4411. run(elm, e => remove$7(SugarElement.fromDom(e), 'display'));
  4412. };
  4413. const hide = elm => {
  4414. run(elm, e => set$1(SugarElement.fromDom(e), 'display', 'none'));
  4415. };
  4416. const isHidden = elm => {
  4417. const $elm = _get(elm);
  4418. return isNonNullable($elm) && is$2(getRaw$1($elm, 'display'), 'none');
  4419. };
  4420. const uniqueId = prefix => (!prefix ? 'mce_' : prefix) + counter++;
  4421. const getOuterHTML = elm => {
  4422. const $elm = _get(elm);
  4423. if (isNonNullable($elm)) {
  4424. return isElement$6($elm.dom) ? $elm.dom.outerHTML : getOuter($elm);
  4425. } else {
  4426. return '';
  4427. }
  4428. };
  4429. const setOuterHTML = (elm, html) => {
  4430. run(elm, $elm => {
  4431. if (isElement$6($elm)) {
  4432. $elm.outerHTML = html;
  4433. }
  4434. });
  4435. };
  4436. const insertAfter = (node, reference) => {
  4437. const referenceNode = get(reference);
  4438. return run(node, node => {
  4439. const parent = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.parentNode;
  4440. const nextSibling = referenceNode === null || referenceNode === void 0 ? void 0 : referenceNode.nextSibling;
  4441. if (parent) {
  4442. if (nextSibling) {
  4443. parent.insertBefore(node, nextSibling);
  4444. } else {
  4445. parent.appendChild(node);
  4446. }
  4447. }
  4448. return node;
  4449. });
  4450. };
  4451. const replace = (newElm, oldElm, keepChildren) => run(oldElm, elm => {
  4452. var _a;
  4453. const replacee = isArray$1(oldElm) ? newElm.cloneNode(true) : newElm;
  4454. if (keepChildren) {
  4455. each$a(grep(elm.childNodes), node => {
  4456. replacee.appendChild(node);
  4457. });
  4458. }
  4459. (_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(replacee, elm);
  4460. return elm;
  4461. });
  4462. const rename = (elm, name) => {
  4463. if (elm.nodeName !== name.toUpperCase()) {
  4464. const newElm = create(name);
  4465. each$a(getAttribs(elm), attrNode => {
  4466. setAttrib(newElm, attrNode.nodeName, getAttrib(elm, attrNode.nodeName));
  4467. });
  4468. replace(newElm, elm, true);
  4469. return newElm;
  4470. } else {
  4471. return elm;
  4472. }
  4473. };
  4474. const findCommonAncestor = (a, b) => {
  4475. let ps = a;
  4476. while (ps) {
  4477. let pe = b;
  4478. while (pe && ps !== pe) {
  4479. pe = pe.parentNode;
  4480. }
  4481. if (ps === pe) {
  4482. break;
  4483. }
  4484. ps = ps.parentNode;
  4485. }
  4486. if (!ps && a.ownerDocument) {
  4487. return a.ownerDocument.documentElement;
  4488. } else {
  4489. return ps;
  4490. }
  4491. };
  4492. const isNonEmptyElement = node => {
  4493. if (isElement$6(node)) {
  4494. const isNamedAnchor = node.nodeName.toLowerCase() === 'a' && !getAttrib(node, 'href') && getAttrib(node, 'id');
  4495. if (getAttrib(node, 'name') || getAttrib(node, 'data-mce-bookmark') || isNamedAnchor) {
  4496. return true;
  4497. }
  4498. }
  4499. return false;
  4500. };
  4501. const isEmpty = (node, elements) => {
  4502. let brCount = 0;
  4503. if (isNonEmptyElement(node)) {
  4504. return false;
  4505. }
  4506. const firstChild = node.firstChild;
  4507. if (firstChild) {
  4508. const walker = new DomTreeWalker(firstChild, node);
  4509. const whitespaceElements = schema ? schema.getWhitespaceElements() : {};
  4510. const nonEmptyElements = elements || (schema ? schema.getNonEmptyElements() : null);
  4511. let tempNode = firstChild;
  4512. do {
  4513. if (isElement$6(tempNode)) {
  4514. const bogusVal = tempNode.getAttribute('data-mce-bogus');
  4515. if (bogusVal) {
  4516. tempNode = walker.next(bogusVal === 'all');
  4517. continue;
  4518. }
  4519. const name = tempNode.nodeName.toLowerCase();
  4520. if (nonEmptyElements && nonEmptyElements[name]) {
  4521. if (name === 'br') {
  4522. brCount++;
  4523. tempNode = walker.next();
  4524. continue;
  4525. }
  4526. return false;
  4527. }
  4528. if (isNonEmptyElement(tempNode)) {
  4529. return false;
  4530. }
  4531. }
  4532. if (isComment(tempNode)) {
  4533. return false;
  4534. }
  4535. if (isText$a(tempNode) && !isWhitespaceText(tempNode.data)) {
  4536. return false;
  4537. }
  4538. if (isText$a(tempNode) && tempNode.parentNode && whitespaceElements[tempNode.parentNode.nodeName] && isWhitespaceText(tempNode.data)) {
  4539. return false;
  4540. }
  4541. tempNode = walker.next();
  4542. } while (tempNode);
  4543. }
  4544. return brCount <= 1;
  4545. };
  4546. const createRng = () => doc.createRange();
  4547. const split = (parentElm, splitElm, replacementElm) => {
  4548. let range = createRng();
  4549. let beforeFragment;
  4550. let afterFragment;
  4551. if (parentElm && splitElm && parentElm.parentNode && splitElm.parentNode) {
  4552. const parentNode = parentElm.parentNode;
  4553. range.setStart(parentNode, findNodeIndex(parentElm));
  4554. range.setEnd(splitElm.parentNode, findNodeIndex(splitElm));
  4555. beforeFragment = range.extractContents();
  4556. range = createRng();
  4557. range.setStart(splitElm.parentNode, findNodeIndex(splitElm) + 1);
  4558. range.setEnd(parentNode, findNodeIndex(parentElm) + 1);
  4559. afterFragment = range.extractContents();
  4560. parentNode.insertBefore(trimNode(self, beforeFragment), parentElm);
  4561. if (replacementElm) {
  4562. parentNode.insertBefore(replacementElm, parentElm);
  4563. } else {
  4564. parentNode.insertBefore(splitElm, parentElm);
  4565. }
  4566. parentNode.insertBefore(trimNode(self, afterFragment), parentElm);
  4567. remove(parentElm);
  4568. return replacementElm || splitElm;
  4569. } else {
  4570. return undefined;
  4571. }
  4572. };
  4573. const bind = (target, name, func, scope) => {
  4574. if (isArray$1(target)) {
  4575. let i = target.length;
  4576. const rv = [];
  4577. while (i--) {
  4578. rv[i] = bind(target[i], name, func, scope);
  4579. }
  4580. return rv;
  4581. } else {
  4582. if (settings.collect && (target === doc || target === win)) {
  4583. boundEvents.push([
  4584. target,
  4585. name,
  4586. func,
  4587. scope
  4588. ]);
  4589. }
  4590. return events.bind(target, name, func, scope || self);
  4591. }
  4592. };
  4593. const unbind = (target, name, func) => {
  4594. if (isArray$1(target)) {
  4595. let i = target.length;
  4596. const rv = [];
  4597. while (i--) {
  4598. rv[i] = unbind(target[i], name, func);
  4599. }
  4600. return rv;
  4601. } else {
  4602. if (boundEvents.length > 0 && (target === doc || target === win)) {
  4603. let i = boundEvents.length;
  4604. while (i--) {
  4605. const [boundTarget, boundName, boundFunc] = boundEvents[i];
  4606. if (target === boundTarget && (!name || name === boundName) && (!func || func === boundFunc)) {
  4607. events.unbind(boundTarget, boundName, boundFunc);
  4608. }
  4609. }
  4610. }
  4611. return events.unbind(target, name, func);
  4612. }
  4613. };
  4614. const dispatch = (target, name, evt) => events.dispatch(target, name, evt);
  4615. const fire = (target, name, evt) => events.dispatch(target, name, evt);
  4616. const getContentEditable = node => {
  4617. if (node && isElement$6(node)) {
  4618. const contentEditable = node.getAttribute('data-mce-contenteditable');
  4619. if (contentEditable && contentEditable !== 'inherit') {
  4620. return contentEditable;
  4621. }
  4622. return node.contentEditable !== 'inherit' ? node.contentEditable : null;
  4623. } else {
  4624. return null;
  4625. }
  4626. };
  4627. const getContentEditableParent = node => {
  4628. const root = getRoot();
  4629. let state = null;
  4630. for (let tempNode = node; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
  4631. state = getContentEditable(tempNode);
  4632. if (state !== null) {
  4633. break;
  4634. }
  4635. }
  4636. return state;
  4637. };
  4638. const destroy = () => {
  4639. if (boundEvents.length > 0) {
  4640. let i = boundEvents.length;
  4641. while (i--) {
  4642. const [boundTarget, boundName, boundFunc] = boundEvents[i];
  4643. events.unbind(boundTarget, boundName, boundFunc);
  4644. }
  4645. }
  4646. each$d(files, (_, url) => {
  4647. styleSheetLoader.unload(url);
  4648. delete files[url];
  4649. });
  4650. };
  4651. const isChildOf = (node, parent) => {
  4652. return node === parent || parent.contains(node);
  4653. };
  4654. const dumpRng = r => 'startContainer: ' + r.startContainer.nodeName + ', startOffset: ' + r.startOffset + ', endContainer: ' + r.endContainer.nodeName + ', endOffset: ' + r.endOffset;
  4655. const self = {
  4656. doc,
  4657. settings,
  4658. win,
  4659. files,
  4660. stdMode,
  4661. boxModel,
  4662. styleSheetLoader,
  4663. boundEvents,
  4664. styles,
  4665. schema,
  4666. events,
  4667. isBlock: isBlock,
  4668. root: null,
  4669. clone,
  4670. getRoot,
  4671. getViewPort,
  4672. getRect,
  4673. getSize,
  4674. getParent,
  4675. getParents: getParents,
  4676. get,
  4677. getNext,
  4678. getPrev,
  4679. select,
  4680. is,
  4681. add,
  4682. create,
  4683. createHTML,
  4684. createFragment,
  4685. remove,
  4686. setStyle,
  4687. getStyle: getStyle,
  4688. setStyles,
  4689. removeAllAttribs,
  4690. setAttrib,
  4691. setAttribs,
  4692. getAttrib,
  4693. getPos: getPos$1,
  4694. parseStyle,
  4695. serializeStyle,
  4696. addStyle,
  4697. loadCSS,
  4698. addClass,
  4699. removeClass,
  4700. hasClass,
  4701. toggleClass,
  4702. show,
  4703. hide,
  4704. isHidden,
  4705. uniqueId,
  4706. setHTML,
  4707. getOuterHTML,
  4708. setOuterHTML,
  4709. decode,
  4710. encode,
  4711. insertAfter,
  4712. replace,
  4713. rename,
  4714. findCommonAncestor,
  4715. run,
  4716. getAttribs,
  4717. isEmpty,
  4718. createRng,
  4719. nodeIndex: findNodeIndex,
  4720. split,
  4721. bind: bind,
  4722. unbind: unbind,
  4723. fire,
  4724. dispatch,
  4725. getContentEditable,
  4726. getContentEditableParent,
  4727. destroy,
  4728. isChildOf,
  4729. dumpRng
  4730. };
  4731. const attrHooks = setupAttrHooks(styles, settings, constant(self));
  4732. return self;
  4733. };
  4734. DOMUtils.DOM = DOMUtils(document);
  4735. DOMUtils.nodeIndex = findNodeIndex;
  4736. const DOM$b = DOMUtils.DOM;
  4737. const QUEUED = 0;
  4738. const LOADING = 1;
  4739. const LOADED = 2;
  4740. const FAILED = 3;
  4741. class ScriptLoader {
  4742. constructor(settings = {}) {
  4743. this.states = {};
  4744. this.queue = [];
  4745. this.scriptLoadedCallbacks = {};
  4746. this.queueLoadedCallbacks = [];
  4747. this.loading = false;
  4748. this.settings = settings;
  4749. }
  4750. _setReferrerPolicy(referrerPolicy) {
  4751. this.settings.referrerPolicy = referrerPolicy;
  4752. }
  4753. loadScript(url) {
  4754. return new Promise((resolve, reject) => {
  4755. const dom = DOM$b;
  4756. let elm;
  4757. const cleanup = () => {
  4758. dom.remove(id);
  4759. if (elm) {
  4760. elm.onerror = elm.onload = elm = null;
  4761. }
  4762. };
  4763. const done = () => {
  4764. cleanup();
  4765. resolve();
  4766. };
  4767. const error = () => {
  4768. cleanup();
  4769. reject('Failed to load script: ' + url);
  4770. };
  4771. const id = dom.uniqueId();
  4772. elm = document.createElement('script');
  4773. elm.id = id;
  4774. elm.type = 'text/javascript';
  4775. elm.src = Tools._addCacheSuffix(url);
  4776. if (this.settings.referrerPolicy) {
  4777. dom.setAttrib(elm, 'referrerpolicy', this.settings.referrerPolicy);
  4778. }
  4779. elm.onload = done;
  4780. elm.onerror = error;
  4781. (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
  4782. });
  4783. }
  4784. isDone(url) {
  4785. return this.states[url] === LOADED;
  4786. }
  4787. markDone(url) {
  4788. this.states[url] = LOADED;
  4789. }
  4790. add(url) {
  4791. const self = this;
  4792. self.queue.push(url);
  4793. const state = self.states[url];
  4794. if (state === undefined) {
  4795. self.states[url] = QUEUED;
  4796. }
  4797. return new Promise((resolve, reject) => {
  4798. if (!self.scriptLoadedCallbacks[url]) {
  4799. self.scriptLoadedCallbacks[url] = [];
  4800. }
  4801. self.scriptLoadedCallbacks[url].push({
  4802. resolve,
  4803. reject
  4804. });
  4805. });
  4806. }
  4807. load(url) {
  4808. return this.add(url);
  4809. }
  4810. remove(url) {
  4811. delete this.states[url];
  4812. delete this.scriptLoadedCallbacks[url];
  4813. }
  4814. loadQueue() {
  4815. const queue = this.queue;
  4816. this.queue = [];
  4817. return this.loadScripts(queue);
  4818. }
  4819. loadScripts(scripts) {
  4820. const self = this;
  4821. const execCallbacks = (name, url) => {
  4822. get$a(self.scriptLoadedCallbacks, url).each(callbacks => {
  4823. each$e(callbacks, callback => callback[name](url));
  4824. });
  4825. delete self.scriptLoadedCallbacks[url];
  4826. };
  4827. const processResults = results => {
  4828. const failures = filter$5(results, result => result.status === 'rejected');
  4829. if (failures.length > 0) {
  4830. return Promise.reject(bind$3(failures, ({reason}) => isArray$1(reason) ? reason : [reason]));
  4831. } else {
  4832. return Promise.resolve();
  4833. }
  4834. };
  4835. const load = urls => Promise.allSettled(map$3(urls, url => {
  4836. if (self.states[url] === LOADED) {
  4837. execCallbacks('resolve', url);
  4838. return Promise.resolve();
  4839. } else if (self.states[url] === FAILED) {
  4840. execCallbacks('reject', url);
  4841. return Promise.reject(url);
  4842. } else {
  4843. self.states[url] = LOADING;
  4844. return self.loadScript(url).then(() => {
  4845. self.states[url] = LOADED;
  4846. execCallbacks('resolve', url);
  4847. const queue = self.queue;
  4848. if (queue.length > 0) {
  4849. self.queue = [];
  4850. return load(queue).then(processResults);
  4851. } else {
  4852. return Promise.resolve();
  4853. }
  4854. }, () => {
  4855. self.states[url] = FAILED;
  4856. execCallbacks('reject', url);
  4857. return Promise.reject(url);
  4858. });
  4859. }
  4860. }));
  4861. const processQueue = urls => {
  4862. self.loading = true;
  4863. return load(urls).then(results => {
  4864. self.loading = false;
  4865. const nextQueuedItem = self.queueLoadedCallbacks.shift();
  4866. Optional.from(nextQueuedItem).each(call);
  4867. return processResults(results);
  4868. });
  4869. };
  4870. const uniqueScripts = stringArray(scripts);
  4871. if (self.loading) {
  4872. return new Promise((resolve, reject) => {
  4873. self.queueLoadedCallbacks.push(() => processQueue(uniqueScripts).then(resolve, reject));
  4874. });
  4875. } else {
  4876. return processQueue(uniqueScripts);
  4877. }
  4878. }
  4879. }
  4880. ScriptLoader.ScriptLoader = new ScriptLoader();
  4881. const Cell = initial => {
  4882. let value = initial;
  4883. const get = () => {
  4884. return value;
  4885. };
  4886. const set = v => {
  4887. value = v;
  4888. };
  4889. return {
  4890. get,
  4891. set
  4892. };
  4893. };
  4894. const isRaw = str => isObject(str) && has$2(str, 'raw');
  4895. const isTokenised = str => isArray$1(str) && str.length > 1;
  4896. const data = {};
  4897. const currentCode = Cell('en');
  4898. const getLanguageData = () => get$a(data, currentCode.get());
  4899. const getData$1 = () => map$2(data, value => ({ ...value }));
  4900. const setCode = newCode => {
  4901. if (newCode) {
  4902. currentCode.set(newCode);
  4903. }
  4904. };
  4905. const getCode = () => currentCode.get();
  4906. const add$1 = (code, items) => {
  4907. let langData = data[code];
  4908. if (!langData) {
  4909. data[code] = langData = {};
  4910. }
  4911. each$d(items, (translation, name) => {
  4912. langData[name.toLowerCase()] = translation;
  4913. });
  4914. };
  4915. const translate = text => {
  4916. const langData = getLanguageData().getOr({});
  4917. const toString = obj => {
  4918. if (isFunction(obj)) {
  4919. return Object.prototype.toString.call(obj);
  4920. }
  4921. return !isEmpty(obj) ? '' + obj : '';
  4922. };
  4923. const isEmpty = text => text === '' || text === null || text === undefined;
  4924. const getLangData = text => {
  4925. const textstr = toString(text);
  4926. return get$a(langData, textstr.toLowerCase()).map(toString).getOr(textstr);
  4927. };
  4928. const removeContext = str => str.replace(/{context:\w+}$/, '');
  4929. if (isEmpty(text)) {
  4930. return '';
  4931. }
  4932. if (isRaw(text)) {
  4933. return toString(text.raw);
  4934. }
  4935. if (isTokenised(text)) {
  4936. const values = text.slice(1);
  4937. const substitued = getLangData(text[0]).replace(/\{([0-9]+)\}/g, ($1, $2) => has$2(values, $2) ? toString(values[$2]) : $1);
  4938. return removeContext(substitued);
  4939. }
  4940. return removeContext(getLangData(text));
  4941. };
  4942. const isRtl$1 = () => getLanguageData().bind(items => get$a(items, '_dir')).exists(dir => dir === 'rtl');
  4943. const hasCode = code => has$2(data, code);
  4944. const I18n = {
  4945. getData: getData$1,
  4946. setCode,
  4947. getCode,
  4948. add: add$1,
  4949. translate,
  4950. isRtl: isRtl$1,
  4951. hasCode
  4952. };
  4953. const AddOnManager = () => {
  4954. const items = [];
  4955. const urls = {};
  4956. const lookup = {};
  4957. const _listeners = [];
  4958. const runListeners = (name, state) => {
  4959. const matchedListeners = filter$5(_listeners, listener => listener.name === name && listener.state === state);
  4960. each$e(matchedListeners, listener => listener.resolve());
  4961. };
  4962. const isLoaded = name => has$2(urls, name);
  4963. const isAdded = name => has$2(lookup, name);
  4964. const get = name => {
  4965. if (lookup[name]) {
  4966. return lookup[name].instance;
  4967. }
  4968. return undefined;
  4969. };
  4970. const loadLanguagePack = (name, languages) => {
  4971. const language = I18n.getCode();
  4972. const wrappedLanguages = ',' + (languages || '') + ',';
  4973. if (!language || languages && wrappedLanguages.indexOf(',' + language + ',') === -1) {
  4974. return;
  4975. }
  4976. ScriptLoader.ScriptLoader.add(urls[name] + '/langs/' + language + '.js');
  4977. };
  4978. const requireLangPack = (name, languages) => {
  4979. if (AddOnManager.languageLoad !== false) {
  4980. if (isLoaded(name)) {
  4981. loadLanguagePack(name, languages);
  4982. } else {
  4983. waitFor(name, 'loaded').then(() => loadLanguagePack(name, languages));
  4984. }
  4985. }
  4986. };
  4987. const add = (id, addOn) => {
  4988. items.push(addOn);
  4989. lookup[id] = { instance: addOn };
  4990. runListeners(id, 'added');
  4991. return addOn;
  4992. };
  4993. const remove = name => {
  4994. delete urls[name];
  4995. delete lookup[name];
  4996. };
  4997. const createUrl = (baseUrl, dep) => {
  4998. if (isString(dep)) {
  4999. return isString(baseUrl) ? {
  5000. prefix: '',
  5001. resource: dep,
  5002. suffix: ''
  5003. } : {
  5004. prefix: baseUrl.prefix,
  5005. resource: dep,
  5006. suffix: baseUrl.suffix
  5007. };
  5008. } else {
  5009. return dep;
  5010. }
  5011. };
  5012. const load = (name, addOnUrl) => {
  5013. if (urls[name]) {
  5014. return Promise.resolve();
  5015. }
  5016. let urlString = isString(addOnUrl) ? addOnUrl : addOnUrl.prefix + addOnUrl.resource + addOnUrl.suffix;
  5017. if (urlString.indexOf('/') !== 0 && urlString.indexOf('://') === -1) {
  5018. urlString = AddOnManager.baseURL + '/' + urlString;
  5019. }
  5020. urls[name] = urlString.substring(0, urlString.lastIndexOf('/'));
  5021. const done = () => {
  5022. runListeners(name, 'loaded');
  5023. return Promise.resolve();
  5024. };
  5025. if (lookup[name]) {
  5026. return done();
  5027. } else {
  5028. return ScriptLoader.ScriptLoader.add(urlString).then(done);
  5029. }
  5030. };
  5031. const waitFor = (name, state = 'added') => {
  5032. if (state === 'added' && isAdded(name)) {
  5033. return Promise.resolve();
  5034. } else if (state === 'loaded' && isLoaded(name)) {
  5035. return Promise.resolve();
  5036. } else {
  5037. return new Promise(resolve => {
  5038. _listeners.push({
  5039. name,
  5040. state,
  5041. resolve
  5042. });
  5043. });
  5044. }
  5045. };
  5046. return {
  5047. items,
  5048. urls,
  5049. lookup,
  5050. get,
  5051. requireLangPack,
  5052. add,
  5053. remove,
  5054. createUrl,
  5055. load,
  5056. waitFor
  5057. };
  5058. };
  5059. AddOnManager.languageLoad = true;
  5060. AddOnManager.baseURL = '';
  5061. AddOnManager.PluginManager = AddOnManager();
  5062. AddOnManager.ThemeManager = AddOnManager();
  5063. AddOnManager.ModelManager = AddOnManager();
  5064. const singleton = doRevoke => {
  5065. const subject = Cell(Optional.none());
  5066. const revoke = () => subject.get().each(doRevoke);
  5067. const clear = () => {
  5068. revoke();
  5069. subject.set(Optional.none());
  5070. };
  5071. const isSet = () => subject.get().isSome();
  5072. const get = () => subject.get();
  5073. const set = s => {
  5074. revoke();
  5075. subject.set(Optional.some(s));
  5076. };
  5077. return {
  5078. clear,
  5079. isSet,
  5080. get,
  5081. set
  5082. };
  5083. };
  5084. const repeatable = delay => {
  5085. const intervalId = Cell(Optional.none());
  5086. const revoke = () => intervalId.get().each(id => clearInterval(id));
  5087. const clear = () => {
  5088. revoke();
  5089. intervalId.set(Optional.none());
  5090. };
  5091. const isSet = () => intervalId.get().isSome();
  5092. const get = () => intervalId.get();
  5093. const set = functionToRepeat => {
  5094. revoke();
  5095. intervalId.set(Optional.some(setInterval(functionToRepeat, delay)));
  5096. };
  5097. return {
  5098. clear,
  5099. isSet,
  5100. get,
  5101. set
  5102. };
  5103. };
  5104. const value$2 = () => {
  5105. const subject = singleton(noop);
  5106. const on = f => subject.get().each(f);
  5107. return {
  5108. ...subject,
  5109. on
  5110. };
  5111. };
  5112. const first$1 = (fn, rate) => {
  5113. let timer = null;
  5114. const cancel = () => {
  5115. if (!isNull(timer)) {
  5116. clearTimeout(timer);
  5117. timer = null;
  5118. }
  5119. };
  5120. const throttle = (...args) => {
  5121. if (isNull(timer)) {
  5122. timer = setTimeout(() => {
  5123. timer = null;
  5124. fn.apply(null, args);
  5125. }, rate);
  5126. }
  5127. };
  5128. return {
  5129. cancel,
  5130. throttle
  5131. };
  5132. };
  5133. const last$1 = (fn, rate) => {
  5134. let timer = null;
  5135. const cancel = () => {
  5136. if (!isNull(timer)) {
  5137. clearTimeout(timer);
  5138. timer = null;
  5139. }
  5140. };
  5141. const throttle = (...args) => {
  5142. cancel();
  5143. timer = setTimeout(() => {
  5144. timer = null;
  5145. fn.apply(null, args);
  5146. }, rate);
  5147. };
  5148. return {
  5149. cancel,
  5150. throttle
  5151. };
  5152. };
  5153. const annotation = constant('mce-annotation');
  5154. const dataAnnotation = constant('data-mce-annotation');
  5155. const dataAnnotationId = constant('data-mce-annotation-uid');
  5156. const dataAnnotationActive = constant('data-mce-annotation-active');
  5157. const dataAnnotationClasses = constant('data-mce-annotation-classes');
  5158. const dataAnnotationAttributes = constant('data-mce-annotation-attrs');
  5159. const isRoot$1 = root => node => eq(node, root);
  5160. const identify = (editor, annotationName) => {
  5161. const rng = editor.selection.getRng();
  5162. const start = SugarElement.fromDom(rng.startContainer);
  5163. const root = SugarElement.fromDom(editor.getBody());
  5164. const selector = annotationName.fold(() => '.' + annotation(), an => `[${ dataAnnotation() }="${ an }"]`);
  5165. const newStart = child$1(start, rng.startOffset).getOr(start);
  5166. const closest = closest$3(newStart, selector, isRoot$1(root));
  5167. return closest.bind(c => getOpt(c, `${ dataAnnotationId() }`).bind(uid => getOpt(c, `${ dataAnnotation() }`).map(name => {
  5168. const elements = findMarkers(editor, uid);
  5169. return {
  5170. uid,
  5171. name,
  5172. elements
  5173. };
  5174. })));
  5175. };
  5176. const isAnnotation = elem => isElement$7(elem) && has(elem, annotation());
  5177. const isBogusElement = (elem, root) => has$1(elem, 'data-mce-bogus') || ancestor$1(elem, '[data-mce-bogus="all"]', isRoot$1(root));
  5178. const findMarkers = (editor, uid) => {
  5179. const body = SugarElement.fromDom(editor.getBody());
  5180. const descendants$1 = descendants(body, `[${ dataAnnotationId() }="${ uid }"]`);
  5181. return filter$5(descendants$1, descendant => !isBogusElement(descendant, body));
  5182. };
  5183. const findAll = (editor, name) => {
  5184. const body = SugarElement.fromDom(editor.getBody());
  5185. const markers = descendants(body, `[${ dataAnnotation() }="${ name }"]`);
  5186. const directory = {};
  5187. each$e(markers, m => {
  5188. if (!isBogusElement(m, body)) {
  5189. const uid = get$9(m, dataAnnotationId());
  5190. const nodesAlready = get$a(directory, uid).getOr([]);
  5191. directory[uid] = nodesAlready.concat([m]);
  5192. }
  5193. });
  5194. return directory;
  5195. };
  5196. const setup$x = (editor, registry) => {
  5197. const changeCallbacks = Cell({});
  5198. const initData = () => ({
  5199. listeners: [],
  5200. previous: value$2()
  5201. });
  5202. const withCallbacks = (name, f) => {
  5203. updateCallbacks(name, data => {
  5204. f(data);
  5205. return data;
  5206. });
  5207. };
  5208. const updateCallbacks = (name, f) => {
  5209. const callbackMap = changeCallbacks.get();
  5210. const data = get$a(callbackMap, name).getOrThunk(initData);
  5211. const outputData = f(data);
  5212. callbackMap[name] = outputData;
  5213. changeCallbacks.set(callbackMap);
  5214. };
  5215. const fireCallbacks = (name, uid, elements) => {
  5216. withCallbacks(name, data => {
  5217. each$e(data.listeners, f => f(true, name, {
  5218. uid,
  5219. nodes: map$3(elements, elem => elem.dom)
  5220. }));
  5221. });
  5222. };
  5223. const fireNoAnnotation = name => {
  5224. withCallbacks(name, data => {
  5225. each$e(data.listeners, f => f(false, name));
  5226. });
  5227. };
  5228. const toggleActiveAttr = (uid, state) => {
  5229. each$e(findMarkers(editor, uid), elem => {
  5230. if (state) {
  5231. set$2(elem, dataAnnotationActive(), 'true');
  5232. } else {
  5233. remove$b(elem, dataAnnotationActive());
  5234. }
  5235. });
  5236. };
  5237. const onNodeChange = last$1(() => {
  5238. const annotations = sort(registry.getNames());
  5239. each$e(annotations, name => {
  5240. updateCallbacks(name, data => {
  5241. const prev = data.previous.get();
  5242. identify(editor, Optional.some(name)).fold(() => {
  5243. prev.each(uid => {
  5244. fireNoAnnotation(name);
  5245. data.previous.clear();
  5246. toggleActiveAttr(uid, false);
  5247. });
  5248. }, ({uid, name, elements}) => {
  5249. if (!is$2(prev, uid)) {
  5250. prev.each(uid => toggleActiveAttr(uid, false));
  5251. fireCallbacks(name, uid, elements);
  5252. data.previous.set(uid);
  5253. toggleActiveAttr(uid, true);
  5254. }
  5255. });
  5256. return {
  5257. previous: data.previous,
  5258. listeners: data.listeners
  5259. };
  5260. });
  5261. });
  5262. }, 30);
  5263. editor.on('remove', () => {
  5264. onNodeChange.cancel();
  5265. });
  5266. editor.on('NodeChange', () => {
  5267. onNodeChange.throttle();
  5268. });
  5269. const addListener = (name, f) => {
  5270. updateCallbacks(name, data => ({
  5271. previous: data.previous,
  5272. listeners: data.listeners.concat([f])
  5273. }));
  5274. };
  5275. return { addListener };
  5276. };
  5277. const setup$w = (editor, registry) => {
  5278. const dataAnnotation$1 = dataAnnotation();
  5279. const identifyParserNode = node => Optional.from(node.attr(dataAnnotation$1)).bind(registry.lookup);
  5280. const removeDirectAnnotation = node => {
  5281. var _a, _b;
  5282. node.attr(dataAnnotationId(), null);
  5283. node.attr(dataAnnotation(), null);
  5284. node.attr(dataAnnotationActive(), null);
  5285. const customAttrNames = Optional.from(node.attr(dataAnnotationAttributes())).map(names => names.split(',')).getOr([]);
  5286. const customClasses = Optional.from(node.attr(dataAnnotationClasses())).map(names => names.split(',')).getOr([]);
  5287. each$e(customAttrNames, name => node.attr(name, null));
  5288. const classList = (_b = (_a = node.attr('class')) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
  5289. const newClassList = difference(classList, [annotation()].concat(customClasses));
  5290. node.attr('class', newClassList.length > 0 ? newClassList.join(' ') : null);
  5291. node.attr(dataAnnotationClasses(), null);
  5292. node.attr(dataAnnotationAttributes(), null);
  5293. };
  5294. editor.serializer.addTempAttr(dataAnnotationActive());
  5295. editor.serializer.addAttributeFilter(dataAnnotation$1, nodes => {
  5296. for (const node of nodes) {
  5297. identifyParserNode(node).each(settings => {
  5298. if (settings.persistent === false) {
  5299. if (node.name === 'span') {
  5300. node.unwrap();
  5301. } else {
  5302. removeDirectAnnotation(node);
  5303. }
  5304. }
  5305. });
  5306. }
  5307. });
  5308. };
  5309. const create$c = () => {
  5310. const annotations = {};
  5311. const register = (name, settings) => {
  5312. annotations[name] = {
  5313. name,
  5314. settings
  5315. };
  5316. };
  5317. const lookup = name => get$a(annotations, name).map(a => a.settings);
  5318. const getNames = () => keys(annotations);
  5319. return {
  5320. register,
  5321. lookup,
  5322. getNames
  5323. };
  5324. };
  5325. let unique = 0;
  5326. const generate$1 = prefix => {
  5327. const date = new Date();
  5328. const time = date.getTime();
  5329. const random = Math.floor(Math.random() * 1000000000);
  5330. unique++;
  5331. return prefix + '_' + random + unique + String(time);
  5332. };
  5333. const add = (element, classes) => {
  5334. each$e(classes, x => {
  5335. add$2(element, x);
  5336. });
  5337. };
  5338. const remove$5 = (element, classes) => {
  5339. each$e(classes, x => {
  5340. remove$8(element, x);
  5341. });
  5342. };
  5343. const clone$2 = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  5344. const shallow$1 = original => clone$2(original, false);
  5345. const deep$1 = original => clone$2(original, true);
  5346. const shallowAs = (original, tag) => {
  5347. const nu = SugarElement.fromTag(tag);
  5348. const attributes = clone$4(original);
  5349. setAll$1(nu, attributes);
  5350. return nu;
  5351. };
  5352. const mutate = (original, tag) => {
  5353. const nu = shallowAs(original, tag);
  5354. after$4(original, nu);
  5355. const children = children$1(original);
  5356. append(nu, children);
  5357. remove$6(original);
  5358. return nu;
  5359. };
  5360. const TextWalker = (startNode, rootNode, isBoundary = never) => {
  5361. const walker = new DomTreeWalker(startNode, rootNode);
  5362. const walk = direction => {
  5363. let next;
  5364. do {
  5365. next = walker[direction]();
  5366. } while (next && !isText$a(next) && !isBoundary(next));
  5367. return Optional.from(next).filter(isText$a);
  5368. };
  5369. return {
  5370. current: () => Optional.from(walker.current()).filter(isText$a),
  5371. next: () => walk('next'),
  5372. prev: () => walk('prev'),
  5373. prev2: () => walk('prev2')
  5374. };
  5375. };
  5376. const TextSeeker = (dom, isBoundary) => {
  5377. const isBlockBoundary = isBoundary ? isBoundary : node => dom.isBlock(node) || isBr$6(node) || isContentEditableFalse$a(node);
  5378. const walk = (node, offset, walker, process) => {
  5379. if (isText$a(node)) {
  5380. const newOffset = process(node, offset, node.data);
  5381. if (newOffset !== -1) {
  5382. return Optional.some({
  5383. container: node,
  5384. offset: newOffset
  5385. });
  5386. }
  5387. }
  5388. return walker().bind(next => walk(next.container, next.offset, walker, process));
  5389. };
  5390. const backwards = (node, offset, process, root) => {
  5391. const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
  5392. return walk(node, offset, () => walker.prev().map(prev => ({
  5393. container: prev,
  5394. offset: prev.length
  5395. })), process).getOrNull();
  5396. };
  5397. const forwards = (node, offset, process, root) => {
  5398. const walker = TextWalker(node, root !== null && root !== void 0 ? root : dom.getRoot(), isBlockBoundary);
  5399. return walk(node, offset, () => walker.next().map(next => ({
  5400. container: next,
  5401. offset: 0
  5402. })), process).getOrNull();
  5403. };
  5404. return {
  5405. backwards,
  5406. forwards
  5407. };
  5408. };
  5409. const round$2 = Math.round;
  5410. const clone$1 = rect => {
  5411. if (!rect) {
  5412. return {
  5413. left: 0,
  5414. top: 0,
  5415. bottom: 0,
  5416. right: 0,
  5417. width: 0,
  5418. height: 0
  5419. };
  5420. }
  5421. return {
  5422. left: round$2(rect.left),
  5423. top: round$2(rect.top),
  5424. bottom: round$2(rect.bottom),
  5425. right: round$2(rect.right),
  5426. width: round$2(rect.width),
  5427. height: round$2(rect.height)
  5428. };
  5429. };
  5430. const collapse = (rect, toStart) => {
  5431. rect = clone$1(rect);
  5432. if (toStart) {
  5433. rect.right = rect.left;
  5434. } else {
  5435. rect.left = rect.left + rect.width;
  5436. rect.right = rect.left;
  5437. }
  5438. rect.width = 0;
  5439. return rect;
  5440. };
  5441. const isEqual = (rect1, rect2) => rect1.left === rect2.left && rect1.top === rect2.top && rect1.bottom === rect2.bottom && rect1.right === rect2.right;
  5442. const isValidOverflow = (overflowY, rect1, rect2) => overflowY >= 0 && overflowY <= Math.min(rect1.height, rect2.height) / 2;
  5443. const isAbove$1 = (rect1, rect2) => {
  5444. const halfHeight = Math.min(rect2.height / 2, rect1.height / 2);
  5445. if (rect1.bottom - halfHeight < rect2.top) {
  5446. return true;
  5447. }
  5448. if (rect1.top > rect2.bottom) {
  5449. return false;
  5450. }
  5451. return isValidOverflow(rect2.top - rect1.bottom, rect1, rect2);
  5452. };
  5453. const isBelow$1 = (rect1, rect2) => {
  5454. if (rect1.top > rect2.bottom) {
  5455. return true;
  5456. }
  5457. if (rect1.bottom < rect2.top) {
  5458. return false;
  5459. }
  5460. return isValidOverflow(rect2.bottom - rect1.top, rect1, rect2);
  5461. };
  5462. const containsXY = (rect, clientX, clientY) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
  5463. const boundingClientRectFromRects = rects => {
  5464. return foldl(rects, (acc, rect) => {
  5465. return acc.fold(() => Optional.some(rect), prevRect => {
  5466. const left = Math.min(rect.left, prevRect.left);
  5467. const top = Math.min(rect.top, prevRect.top);
  5468. const right = Math.max(rect.right, prevRect.right);
  5469. const bottom = Math.max(rect.bottom, prevRect.bottom);
  5470. return Optional.some({
  5471. top,
  5472. right,
  5473. bottom,
  5474. left,
  5475. width: right - left,
  5476. height: bottom - top
  5477. });
  5478. });
  5479. }, Optional.none());
  5480. };
  5481. const distanceToRectEdgeFromXY = (rect, x, y) => {
  5482. const cx = Math.max(Math.min(x, rect.left + rect.width), rect.left);
  5483. const cy = Math.max(Math.min(y, rect.top + rect.height), rect.top);
  5484. return Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
  5485. };
  5486. const overlapY = (r1, r2) => Math.max(0, Math.min(r1.bottom, r2.bottom) - Math.max(r1.top, r2.top));
  5487. const clamp$2 = (value, min, max) => Math.min(Math.max(value, min), max);
  5488. const getSelectedNode = range => {
  5489. const startContainer = range.startContainer, startOffset = range.startOffset;
  5490. if (startContainer === range.endContainer && startContainer.hasChildNodes() && range.endOffset === startOffset + 1) {
  5491. return startContainer.childNodes[startOffset];
  5492. }
  5493. return null;
  5494. };
  5495. const getNode$1 = (container, offset) => {
  5496. if (isElement$6(container) && container.hasChildNodes()) {
  5497. const childNodes = container.childNodes;
  5498. const safeOffset = clamp$2(offset, 0, childNodes.length - 1);
  5499. return childNodes[safeOffset];
  5500. } else {
  5501. return container;
  5502. }
  5503. };
  5504. const getNodeUnsafe = (container, offset) => {
  5505. if (offset < 0 && isElement$6(container) && container.hasChildNodes()) {
  5506. return undefined;
  5507. } else {
  5508. return getNode$1(container, offset);
  5509. }
  5510. };
  5511. const extendingChars = new RegExp('[\u0300-\u036f\u0483-\u0487\u0488-\u0489\u0591-\u05bd\u05bf\u05c1-\u05c2\u05c4-\u05c5\u05c7\u0610-\u061a' + '\u064b-\u065f\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7-\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0' + '\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e3-\u0902\u093a\u093c' + '\u0941-\u0948\u094d\u0951-\u0957\u0962-\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2-\u09e3' + '\u0a01-\u0a02\u0a3c\u0a41-\u0a42\u0a47-\u0a48\u0a4b-\u0a4d\u0a51\u0a70-\u0a71\u0a75\u0a81-\u0a82\u0abc' + '\u0ac1-\u0ac5\u0ac7-\u0ac8\u0acd\u0ae2-\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57' + '\u0b62-\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c00\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55-\u0c56' + '\u0c62-\u0c63\u0c81\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc-\u0ccd\u0cd5-\u0cd6\u0ce2-\u0ce3\u0d01\u0d3e\u0d41-\u0d44' + '\u0d4d\u0d57\u0d62-\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9' + '\u0ebb-\u0ebc\u0ec8-\u0ecd\u0f18-\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86-\u0f87\u0f8d-\u0f97' + '\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039-\u103a\u103d-\u103e\u1058-\u1059\u105e-\u1060\u1071-\u1074' + '\u1082\u1085-\u1086\u108d\u109d\u135d-\u135f\u1712-\u1714\u1732-\u1734\u1752-\u1753\u1772-\u1773\u17b4-\u17b5' + '\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927-\u1928\u1932\u1939-\u193b\u1a17-\u1a18' + '\u1a1b\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1ab0-\u1abd\u1ABE\u1b00-\u1b03\u1b34' + '\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80-\u1b81\u1ba2-\u1ba5\u1ba8-\u1ba9\u1bab-\u1bad\u1be6\u1be8-\u1be9' + '\u1bed\u1bef-\u1bf1\u1c2c-\u1c33\u1c36-\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1cf4\u1cf8-\u1cf9' + '\u1dc0-\u1df5\u1dfc-\u1dff\u200c-\u200d\u20d0-\u20dc\u20DD-\u20E0\u20e1\u20E2-\u20E4\u20e5-\u20f0\u2cef-\u2cf1' + '\u2d7f\u2de0-\u2dff\u302a-\u302d\u302e-\u302f\u3099-\u309a\ua66f\uA670-\uA672\ua674-\ua67d\ua69e-\ua69f\ua6f0-\ua6f1' + '\ua802\ua806\ua80b\ua825-\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc' + '\ua9e5\uaa29-\uaa2e\uaa31-\uaa32\uaa35-\uaa36\uaa43\uaa4c\uaa7c\uaab0\uaab2-\uaab4\uaab7-\uaab8\uaabe-\uaabf\uaac1' + '\uaaec-\uaaed\uaaf6\uabe5\uabe8\uabed\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\uff9e-\uff9f]');
  5512. const isExtendingChar = ch => isString(ch) && ch.charCodeAt(0) >= 768 && extendingChars.test(ch);
  5513. const or = (...args) => {
  5514. return x => {
  5515. for (let i = 0; i < args.length; i++) {
  5516. if (args[i](x)) {
  5517. return true;
  5518. }
  5519. }
  5520. return false;
  5521. };
  5522. };
  5523. const and = (...args) => {
  5524. return x => {
  5525. for (let i = 0; i < args.length; i++) {
  5526. if (!args[i](x)) {
  5527. return false;
  5528. }
  5529. }
  5530. return true;
  5531. };
  5532. };
  5533. const isElement$4 = isElement$6;
  5534. const isCaretCandidate$2 = isCaretCandidate$3;
  5535. const isBlock$1 = matchStyleValues('display', 'block table');
  5536. const isFloated = matchStyleValues('float', 'left right');
  5537. const isValidElementCaretCandidate = and(isElement$4, isCaretCandidate$2, not(isFloated));
  5538. const isNotPre = not(matchStyleValues('white-space', 'pre pre-line pre-wrap'));
  5539. const isText$7 = isText$a;
  5540. const isBr$3 = isBr$6;
  5541. const nodeIndex$1 = DOMUtils.nodeIndex;
  5542. const resolveIndex$1 = getNodeUnsafe;
  5543. const createRange$1 = doc => doc ? doc.createRange() : DOMUtils.DOM.createRng();
  5544. const isWhiteSpace$1 = chr => isString(chr) && /[\r\n\t ]/.test(chr);
  5545. const isRange = rng => !!rng.setStart && !!rng.setEnd;
  5546. const isHiddenWhiteSpaceRange = range => {
  5547. const container = range.startContainer;
  5548. const offset = range.startOffset;
  5549. if (isWhiteSpace$1(range.toString()) && isNotPre(container.parentNode) && isText$a(container)) {
  5550. const text = container.data;
  5551. if (isWhiteSpace$1(text[offset - 1]) || isWhiteSpace$1(text[offset + 1])) {
  5552. return true;
  5553. }
  5554. }
  5555. return false;
  5556. };
  5557. const getBrClientRect = brNode => {
  5558. const doc = brNode.ownerDocument;
  5559. const rng = createRange$1(doc);
  5560. const nbsp$1 = doc.createTextNode(nbsp);
  5561. const parentNode = brNode.parentNode;
  5562. parentNode.insertBefore(nbsp$1, brNode);
  5563. rng.setStart(nbsp$1, 0);
  5564. rng.setEnd(nbsp$1, 1);
  5565. const clientRect = clone$1(rng.getBoundingClientRect());
  5566. parentNode.removeChild(nbsp$1);
  5567. return clientRect;
  5568. };
  5569. const getBoundingClientRectWebKitText = rng => {
  5570. const sc = rng.startContainer;
  5571. const ec = rng.endContainer;
  5572. const so = rng.startOffset;
  5573. const eo = rng.endOffset;
  5574. if (sc === ec && isText$a(ec) && so === 0 && eo === 1) {
  5575. const newRng = rng.cloneRange();
  5576. newRng.setEndAfter(ec);
  5577. return getBoundingClientRect$1(newRng);
  5578. } else {
  5579. return null;
  5580. }
  5581. };
  5582. const isZeroRect = r => r.left === 0 && r.right === 0 && r.top === 0 && r.bottom === 0;
  5583. const getBoundingClientRect$1 = item => {
  5584. var _a;
  5585. let clientRect;
  5586. const clientRects = item.getClientRects();
  5587. if (clientRects.length > 0) {
  5588. clientRect = clone$1(clientRects[0]);
  5589. } else {
  5590. clientRect = clone$1(item.getBoundingClientRect());
  5591. }
  5592. if (!isRange(item) && isBr$3(item) && isZeroRect(clientRect)) {
  5593. return getBrClientRect(item);
  5594. }
  5595. if (isZeroRect(clientRect) && isRange(item)) {
  5596. return (_a = getBoundingClientRectWebKitText(item)) !== null && _a !== void 0 ? _a : clientRect;
  5597. }
  5598. return clientRect;
  5599. };
  5600. const collapseAndInflateWidth = (clientRect, toStart) => {
  5601. const newClientRect = collapse(clientRect, toStart);
  5602. newClientRect.width = 1;
  5603. newClientRect.right = newClientRect.left + 1;
  5604. return newClientRect;
  5605. };
  5606. const getCaretPositionClientRects = caretPosition => {
  5607. const clientRects = [];
  5608. const addUniqueAndValidRect = clientRect => {
  5609. if (clientRect.height === 0) {
  5610. return;
  5611. }
  5612. if (clientRects.length > 0) {
  5613. if (isEqual(clientRect, clientRects[clientRects.length - 1])) {
  5614. return;
  5615. }
  5616. }
  5617. clientRects.push(clientRect);
  5618. };
  5619. const addCharacterOffset = (container, offset) => {
  5620. const range = createRange$1(container.ownerDocument);
  5621. if (offset < container.data.length) {
  5622. if (isExtendingChar(container.data[offset])) {
  5623. return;
  5624. }
  5625. if (isExtendingChar(container.data[offset - 1])) {
  5626. range.setStart(container, offset);
  5627. range.setEnd(container, offset + 1);
  5628. if (!isHiddenWhiteSpaceRange(range)) {
  5629. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
  5630. return;
  5631. }
  5632. }
  5633. }
  5634. if (offset > 0) {
  5635. range.setStart(container, offset - 1);
  5636. range.setEnd(container, offset);
  5637. if (!isHiddenWhiteSpaceRange(range)) {
  5638. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), false));
  5639. }
  5640. }
  5641. if (offset < container.data.length) {
  5642. range.setStart(container, offset);
  5643. range.setEnd(container, offset + 1);
  5644. if (!isHiddenWhiteSpaceRange(range)) {
  5645. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(range), true));
  5646. }
  5647. }
  5648. };
  5649. const container = caretPosition.container();
  5650. const offset = caretPosition.offset();
  5651. if (isText$7(container)) {
  5652. addCharacterOffset(container, offset);
  5653. return clientRects;
  5654. }
  5655. if (isElement$4(container)) {
  5656. if (caretPosition.isAtEnd()) {
  5657. const node = resolveIndex$1(container, offset);
  5658. if (isText$7(node)) {
  5659. addCharacterOffset(node, node.data.length);
  5660. }
  5661. if (isValidElementCaretCandidate(node) && !isBr$3(node)) {
  5662. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
  5663. }
  5664. } else {
  5665. const node = resolveIndex$1(container, offset);
  5666. if (isText$7(node)) {
  5667. addCharacterOffset(node, 0);
  5668. }
  5669. if (isValidElementCaretCandidate(node) && caretPosition.isAtEnd()) {
  5670. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), false));
  5671. return clientRects;
  5672. }
  5673. const beforeNode = resolveIndex$1(caretPosition.container(), caretPosition.offset() - 1);
  5674. if (isValidElementCaretCandidate(beforeNode) && !isBr$3(beforeNode)) {
  5675. if (isBlock$1(beforeNode) || isBlock$1(node) || !isValidElementCaretCandidate(node)) {
  5676. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(beforeNode), false));
  5677. }
  5678. }
  5679. if (isValidElementCaretCandidate(node)) {
  5680. addUniqueAndValidRect(collapseAndInflateWidth(getBoundingClientRect$1(node), true));
  5681. }
  5682. }
  5683. }
  5684. return clientRects;
  5685. };
  5686. const CaretPosition = (container, offset, clientRects) => {
  5687. const isAtStart = () => {
  5688. if (isText$7(container)) {
  5689. return offset === 0;
  5690. }
  5691. return offset === 0;
  5692. };
  5693. const isAtEnd = () => {
  5694. if (isText$7(container)) {
  5695. return offset >= container.data.length;
  5696. }
  5697. return offset >= container.childNodes.length;
  5698. };
  5699. const toRange = () => {
  5700. const range = createRange$1(container.ownerDocument);
  5701. range.setStart(container, offset);
  5702. range.setEnd(container, offset);
  5703. return range;
  5704. };
  5705. const getClientRects = () => {
  5706. if (!clientRects) {
  5707. clientRects = getCaretPositionClientRects(CaretPosition(container, offset));
  5708. }
  5709. return clientRects;
  5710. };
  5711. const isVisible = () => getClientRects().length > 0;
  5712. const isEqual = caretPosition => caretPosition && container === caretPosition.container() && offset === caretPosition.offset();
  5713. const getNode = before => resolveIndex$1(container, before ? offset - 1 : offset);
  5714. return {
  5715. container: constant(container),
  5716. offset: constant(offset),
  5717. toRange,
  5718. getClientRects,
  5719. isVisible,
  5720. isAtStart,
  5721. isAtEnd,
  5722. isEqual,
  5723. getNode
  5724. };
  5725. };
  5726. CaretPosition.fromRangeStart = range => CaretPosition(range.startContainer, range.startOffset);
  5727. CaretPosition.fromRangeEnd = range => CaretPosition(range.endContainer, range.endOffset);
  5728. CaretPosition.after = node => CaretPosition(node.parentNode, nodeIndex$1(node) + 1);
  5729. CaretPosition.before = node => CaretPosition(node.parentNode, nodeIndex$1(node));
  5730. CaretPosition.isAbove = (pos1, pos2) => lift2(head(pos2.getClientRects()), last$3(pos1.getClientRects()), isAbove$1).getOr(false);
  5731. CaretPosition.isBelow = (pos1, pos2) => lift2(last$3(pos2.getClientRects()), head(pos1.getClientRects()), isBelow$1).getOr(false);
  5732. CaretPosition.isAtStart = pos => pos ? pos.isAtStart() : false;
  5733. CaretPosition.isAtEnd = pos => pos ? pos.isAtEnd() : false;
  5734. CaretPosition.isTextPosition = pos => pos ? isText$a(pos.container()) : false;
  5735. CaretPosition.isElementPosition = pos => !CaretPosition.isTextPosition(pos);
  5736. const trimEmptyTextNode$1 = (dom, node) => {
  5737. if (isText$a(node) && node.data.length === 0) {
  5738. dom.remove(node);
  5739. }
  5740. };
  5741. const insertNode = (dom, rng, node) => {
  5742. rng.insertNode(node);
  5743. trimEmptyTextNode$1(dom, node.previousSibling);
  5744. trimEmptyTextNode$1(dom, node.nextSibling);
  5745. };
  5746. const insertFragment = (dom, rng, frag) => {
  5747. const firstChild = Optional.from(frag.firstChild);
  5748. const lastChild = Optional.from(frag.lastChild);
  5749. rng.insertNode(frag);
  5750. firstChild.each(child => trimEmptyTextNode$1(dom, child.previousSibling));
  5751. lastChild.each(child => trimEmptyTextNode$1(dom, child.nextSibling));
  5752. };
  5753. const rangeInsertNode = (dom, rng, node) => {
  5754. if (isDocumentFragment(node)) {
  5755. insertFragment(dom, rng, node);
  5756. } else {
  5757. insertNode(dom, rng, node);
  5758. }
  5759. };
  5760. const isText$6 = isText$a;
  5761. const isBogus = isBogus$2;
  5762. const nodeIndex = DOMUtils.nodeIndex;
  5763. const normalizedParent = node => {
  5764. const parentNode = node.parentNode;
  5765. if (isBogus(parentNode)) {
  5766. return normalizedParent(parentNode);
  5767. }
  5768. return parentNode;
  5769. };
  5770. const getChildNodes = node => {
  5771. if (!node) {
  5772. return [];
  5773. }
  5774. return reduce(node.childNodes, (result, node) => {
  5775. if (isBogus(node) && node.nodeName !== 'BR') {
  5776. result = result.concat(getChildNodes(node));
  5777. } else {
  5778. result.push(node);
  5779. }
  5780. return result;
  5781. }, []);
  5782. };
  5783. const normalizedTextOffset = (node, offset) => {
  5784. let tempNode = node;
  5785. while (tempNode = tempNode.previousSibling) {
  5786. if (!isText$6(tempNode)) {
  5787. break;
  5788. }
  5789. offset += tempNode.data.length;
  5790. }
  5791. return offset;
  5792. };
  5793. const equal = a => b => a === b;
  5794. const normalizedNodeIndex = node => {
  5795. let nodes, index;
  5796. nodes = getChildNodes(normalizedParent(node));
  5797. index = findIndex$1(nodes, equal(node), node);
  5798. nodes = nodes.slice(0, index + 1);
  5799. const numTextFragments = reduce(nodes, (result, node, i) => {
  5800. if (isText$6(node) && isText$6(nodes[i - 1])) {
  5801. result++;
  5802. }
  5803. return result;
  5804. }, 0);
  5805. nodes = filter$3(nodes, matchNodeNames([node.nodeName]));
  5806. index = findIndex$1(nodes, equal(node), node);
  5807. return index - numTextFragments;
  5808. };
  5809. const createPathItem = node => {
  5810. const name = isText$6(node) ? 'text()' : node.nodeName.toLowerCase();
  5811. return name + '[' + normalizedNodeIndex(node) + ']';
  5812. };
  5813. const parentsUntil$1 = (root, node, predicate) => {
  5814. const parents = [];
  5815. for (let tempNode = node.parentNode; tempNode && tempNode !== root; tempNode = tempNode.parentNode) {
  5816. if (predicate && predicate(tempNode)) {
  5817. break;
  5818. }
  5819. parents.push(tempNode);
  5820. }
  5821. return parents;
  5822. };
  5823. const create$b = (root, caretPosition) => {
  5824. let path = [];
  5825. let container = caretPosition.container();
  5826. let offset = caretPosition.offset();
  5827. let outputOffset;
  5828. if (isText$6(container)) {
  5829. outputOffset = normalizedTextOffset(container, offset);
  5830. } else {
  5831. const childNodes = container.childNodes;
  5832. if (offset >= childNodes.length) {
  5833. outputOffset = 'after';
  5834. offset = childNodes.length - 1;
  5835. } else {
  5836. outputOffset = 'before';
  5837. }
  5838. container = childNodes[offset];
  5839. }
  5840. path.push(createPathItem(container));
  5841. let parents = parentsUntil$1(root, container);
  5842. parents = filter$3(parents, not(isBogus$2));
  5843. path = path.concat(map$1(parents, node => {
  5844. return createPathItem(node);
  5845. }));
  5846. return path.reverse().join('/') + ',' + outputOffset;
  5847. };
  5848. const resolvePathItem = (node, name, index) => {
  5849. let nodes = getChildNodes(node);
  5850. nodes = filter$3(nodes, (node, index) => {
  5851. return !isText$6(node) || !isText$6(nodes[index - 1]);
  5852. });
  5853. nodes = filter$3(nodes, matchNodeNames([name]));
  5854. return nodes[index];
  5855. };
  5856. const findTextPosition = (container, offset) => {
  5857. let node = container;
  5858. let targetOffset = 0;
  5859. while (isText$6(node)) {
  5860. const dataLen = node.data.length;
  5861. if (offset >= targetOffset && offset <= targetOffset + dataLen) {
  5862. container = node;
  5863. offset = offset - targetOffset;
  5864. break;
  5865. }
  5866. if (!isText$6(node.nextSibling)) {
  5867. container = node;
  5868. offset = dataLen;
  5869. break;
  5870. }
  5871. targetOffset += dataLen;
  5872. node = node.nextSibling;
  5873. }
  5874. if (isText$6(container) && offset > container.data.length) {
  5875. offset = container.data.length;
  5876. }
  5877. return CaretPosition(container, offset);
  5878. };
  5879. const resolve$1 = (root, path) => {
  5880. if (!path) {
  5881. return null;
  5882. }
  5883. const parts = path.split(',');
  5884. const paths = parts[0].split('/');
  5885. const offset = parts.length > 1 ? parts[1] : 'before';
  5886. const container = reduce(paths, (result, value) => {
  5887. const match = /([\w\-\(\)]+)\[([0-9]+)\]/.exec(value);
  5888. if (!match) {
  5889. return null;
  5890. }
  5891. if (match[1] === 'text()') {
  5892. match[1] = '#text';
  5893. }
  5894. return resolvePathItem(result, match[1], parseInt(match[2], 10));
  5895. }, root);
  5896. if (!container) {
  5897. return null;
  5898. }
  5899. if (!isText$6(container) && container.parentNode) {
  5900. let nodeOffset;
  5901. if (offset === 'after') {
  5902. nodeOffset = nodeIndex(container) + 1;
  5903. } else {
  5904. nodeOffset = nodeIndex(container);
  5905. }
  5906. return CaretPosition(container.parentNode, nodeOffset);
  5907. }
  5908. return findTextPosition(container, parseInt(offset, 10));
  5909. };
  5910. const isContentEditableFalse$8 = isContentEditableFalse$a;
  5911. const getNormalizedTextOffset$1 = (trim, container, offset) => {
  5912. let trimmedOffset = trim(container.data.slice(0, offset)).length;
  5913. for (let node = container.previousSibling; node && isText$a(node); node = node.previousSibling) {
  5914. trimmedOffset += trim(node.data).length;
  5915. }
  5916. return trimmedOffset;
  5917. };
  5918. const getPoint = (dom, trim, normalized, rng, start) => {
  5919. const container = start ? rng.startContainer : rng.endContainer;
  5920. let offset = start ? rng.startOffset : rng.endOffset;
  5921. const point = [];
  5922. const root = dom.getRoot();
  5923. if (isText$a(container)) {
  5924. point.push(normalized ? getNormalizedTextOffset$1(trim, container, offset) : offset);
  5925. } else {
  5926. let after = 0;
  5927. const childNodes = container.childNodes;
  5928. if (offset >= childNodes.length && childNodes.length) {
  5929. after = 1;
  5930. offset = Math.max(0, childNodes.length - 1);
  5931. }
  5932. point.push(dom.nodeIndex(childNodes[offset], normalized) + after);
  5933. }
  5934. for (let node = container; node && node !== root; node = node.parentNode) {
  5935. point.push(dom.nodeIndex(node, normalized));
  5936. }
  5937. return point;
  5938. };
  5939. const getLocation = (trim, selection, normalized, rng) => {
  5940. const dom = selection.dom;
  5941. const start = getPoint(dom, trim, normalized, rng, true);
  5942. const forward = selection.isForward();
  5943. const fakeCaret = isRangeInCaretContainerBlock(rng) ? { isFakeCaret: true } : {};
  5944. if (!selection.isCollapsed()) {
  5945. const end = getPoint(dom, trim, normalized, rng, false);
  5946. return {
  5947. start,
  5948. end,
  5949. forward,
  5950. ...fakeCaret
  5951. };
  5952. } else {
  5953. return {
  5954. start,
  5955. forward,
  5956. ...fakeCaret
  5957. };
  5958. }
  5959. };
  5960. const findIndex = (dom, name, element) => {
  5961. let count = 0;
  5962. Tools.each(dom.select(name), node => {
  5963. if (node.getAttribute('data-mce-bogus') === 'all') {
  5964. return;
  5965. } else if (node === element) {
  5966. return false;
  5967. } else {
  5968. count++;
  5969. return;
  5970. }
  5971. });
  5972. return count;
  5973. };
  5974. const moveEndPoint$1 = (rng, start) => {
  5975. let container = start ? rng.startContainer : rng.endContainer;
  5976. let offset = start ? rng.startOffset : rng.endOffset;
  5977. if (isElement$6(container) && container.nodeName === 'TR') {
  5978. const childNodes = container.childNodes;
  5979. container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
  5980. if (container) {
  5981. offset = start ? 0 : container.childNodes.length;
  5982. if (start) {
  5983. rng.setStart(container, offset);
  5984. } else {
  5985. rng.setEnd(container, offset);
  5986. }
  5987. }
  5988. }
  5989. };
  5990. const normalizeTableCellSelection = rng => {
  5991. moveEndPoint$1(rng, true);
  5992. moveEndPoint$1(rng, false);
  5993. return rng;
  5994. };
  5995. const findSibling = (node, offset) => {
  5996. if (isElement$6(node)) {
  5997. node = getNode$1(node, offset);
  5998. if (isContentEditableFalse$8(node)) {
  5999. return node;
  6000. }
  6001. }
  6002. if (isCaretContainer$2(node)) {
  6003. if (isText$a(node) && isCaretContainerBlock$1(node)) {
  6004. node = node.parentNode;
  6005. }
  6006. let sibling = node.previousSibling;
  6007. if (isContentEditableFalse$8(sibling)) {
  6008. return sibling;
  6009. }
  6010. sibling = node.nextSibling;
  6011. if (isContentEditableFalse$8(sibling)) {
  6012. return sibling;
  6013. }
  6014. }
  6015. return undefined;
  6016. };
  6017. const findAdjacentContentEditableFalseElm = rng => {
  6018. return findSibling(rng.startContainer, rng.startOffset) || findSibling(rng.endContainer, rng.endOffset);
  6019. };
  6020. const getOffsetBookmark = (trim, normalized, selection) => {
  6021. const element = selection.getNode();
  6022. const rng = selection.getRng();
  6023. if (element.nodeName === 'IMG' || isContentEditableFalse$8(element)) {
  6024. const name = element.nodeName;
  6025. return {
  6026. name,
  6027. index: findIndex(selection.dom, name, element)
  6028. };
  6029. }
  6030. const sibling = findAdjacentContentEditableFalseElm(rng);
  6031. if (sibling) {
  6032. const name = sibling.tagName;
  6033. return {
  6034. name,
  6035. index: findIndex(selection.dom, name, sibling)
  6036. };
  6037. }
  6038. return getLocation(trim, selection, normalized, rng);
  6039. };
  6040. const getCaretBookmark = selection => {
  6041. const rng = selection.getRng();
  6042. return {
  6043. start: create$b(selection.dom.getRoot(), CaretPosition.fromRangeStart(rng)),
  6044. end: create$b(selection.dom.getRoot(), CaretPosition.fromRangeEnd(rng)),
  6045. forward: selection.isForward()
  6046. };
  6047. };
  6048. const getRangeBookmark = selection => {
  6049. return {
  6050. rng: selection.getRng(),
  6051. forward: selection.isForward()
  6052. };
  6053. };
  6054. const createBookmarkSpan = (dom, id, filled) => {
  6055. const args = {
  6056. 'data-mce-type': 'bookmark',
  6057. id,
  6058. 'style': 'overflow:hidden;line-height:0px'
  6059. };
  6060. return filled ? dom.create('span', args, '&#xFEFF;') : dom.create('span', args);
  6061. };
  6062. const getPersistentBookmark = (selection, filled) => {
  6063. const dom = selection.dom;
  6064. let rng = selection.getRng();
  6065. const id = dom.uniqueId();
  6066. const collapsed = selection.isCollapsed();
  6067. const element = selection.getNode();
  6068. const name = element.nodeName;
  6069. const forward = selection.isForward();
  6070. if (name === 'IMG') {
  6071. return {
  6072. name,
  6073. index: findIndex(dom, name, element)
  6074. };
  6075. }
  6076. const rng2 = normalizeTableCellSelection(rng.cloneRange());
  6077. if (!collapsed) {
  6078. rng2.collapse(false);
  6079. const endBookmarkNode = createBookmarkSpan(dom, id + '_end', filled);
  6080. rangeInsertNode(dom, rng2, endBookmarkNode);
  6081. }
  6082. rng = normalizeTableCellSelection(rng);
  6083. rng.collapse(true);
  6084. const startBookmarkNode = createBookmarkSpan(dom, id + '_start', filled);
  6085. rangeInsertNode(dom, rng, startBookmarkNode);
  6086. selection.moveToBookmark({
  6087. id,
  6088. keep: true,
  6089. forward
  6090. });
  6091. return {
  6092. id,
  6093. forward
  6094. };
  6095. };
  6096. const getBookmark$2 = (selection, type, normalized = false) => {
  6097. if (type === 2) {
  6098. return getOffsetBookmark(trim$1, normalized, selection);
  6099. } else if (type === 3) {
  6100. return getCaretBookmark(selection);
  6101. } else if (type) {
  6102. return getRangeBookmark(selection);
  6103. } else {
  6104. return getPersistentBookmark(selection, false);
  6105. }
  6106. };
  6107. const getUndoBookmark = curry(getOffsetBookmark, identity, true);
  6108. const value$1 = value => {
  6109. const applyHelper = fn => fn(value);
  6110. const constHelper = constant(value);
  6111. const outputHelper = () => output;
  6112. const output = {
  6113. tag: true,
  6114. inner: value,
  6115. fold: (_onError, onValue) => onValue(value),
  6116. isValue: always,
  6117. isError: never,
  6118. map: mapper => Result.value(mapper(value)),
  6119. mapError: outputHelper,
  6120. bind: applyHelper,
  6121. exists: applyHelper,
  6122. forall: applyHelper,
  6123. getOr: constHelper,
  6124. or: outputHelper,
  6125. getOrThunk: constHelper,
  6126. orThunk: outputHelper,
  6127. getOrDie: constHelper,
  6128. each: fn => {
  6129. fn(value);
  6130. },
  6131. toOptional: () => Optional.some(value)
  6132. };
  6133. return output;
  6134. };
  6135. const error = error => {
  6136. const outputHelper = () => output;
  6137. const output = {
  6138. tag: false,
  6139. inner: error,
  6140. fold: (onError, _onValue) => onError(error),
  6141. isValue: never,
  6142. isError: always,
  6143. map: outputHelper,
  6144. mapError: mapper => Result.error(mapper(error)),
  6145. bind: outputHelper,
  6146. exists: never,
  6147. forall: always,
  6148. getOr: identity,
  6149. or: identity,
  6150. getOrThunk: apply$1,
  6151. orThunk: apply$1,
  6152. getOrDie: die(String(error)),
  6153. each: noop,
  6154. toOptional: Optional.none
  6155. };
  6156. return output;
  6157. };
  6158. const fromOption = (optional, err) => optional.fold(() => error(err), value$1);
  6159. const Result = {
  6160. value: value$1,
  6161. error,
  6162. fromOption
  6163. };
  6164. const generate = cases => {
  6165. if (!isArray$1(cases)) {
  6166. throw new Error('cases must be an array');
  6167. }
  6168. if (cases.length === 0) {
  6169. throw new Error('there must be at least one case');
  6170. }
  6171. const constructors = [];
  6172. const adt = {};
  6173. each$e(cases, (acase, count) => {
  6174. const keys$1 = keys(acase);
  6175. if (keys$1.length !== 1) {
  6176. throw new Error('one and only one name per case');
  6177. }
  6178. const key = keys$1[0];
  6179. const value = acase[key];
  6180. if (adt[key] !== undefined) {
  6181. throw new Error('duplicate key detected:' + key);
  6182. } else if (key === 'cata') {
  6183. throw new Error('cannot have a case named cata (sorry)');
  6184. } else if (!isArray$1(value)) {
  6185. throw new Error('case arguments must be an array');
  6186. }
  6187. constructors.push(key);
  6188. adt[key] = (...args) => {
  6189. const argLength = args.length;
  6190. if (argLength !== value.length) {
  6191. throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
  6192. }
  6193. const match = branches => {
  6194. const branchKeys = keys(branches);
  6195. if (constructors.length !== branchKeys.length) {
  6196. throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
  6197. }
  6198. const allReqd = forall(constructors, reqKey => {
  6199. return contains$2(branchKeys, reqKey);
  6200. });
  6201. if (!allReqd) {
  6202. throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
  6203. }
  6204. return branches[key].apply(null, args);
  6205. };
  6206. return {
  6207. fold: (...foldArgs) => {
  6208. if (foldArgs.length !== cases.length) {
  6209. throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
  6210. }
  6211. const target = foldArgs[count];
  6212. return target.apply(null, args);
  6213. },
  6214. match,
  6215. log: label => {
  6216. console.log(label, {
  6217. constructors,
  6218. constructor: key,
  6219. params: args
  6220. });
  6221. }
  6222. };
  6223. };
  6224. });
  6225. return adt;
  6226. };
  6227. const Adt = { generate };
  6228. Adt.generate([
  6229. {
  6230. bothErrors: [
  6231. 'error1',
  6232. 'error2'
  6233. ]
  6234. },
  6235. {
  6236. firstError: [
  6237. 'error1',
  6238. 'value2'
  6239. ]
  6240. },
  6241. {
  6242. secondError: [
  6243. 'value1',
  6244. 'error2'
  6245. ]
  6246. },
  6247. {
  6248. bothValues: [
  6249. 'value1',
  6250. 'value2'
  6251. ]
  6252. }
  6253. ]);
  6254. const partition$1 = results => {
  6255. const errors = [];
  6256. const values = [];
  6257. each$e(results, result => {
  6258. result.fold(err => {
  6259. errors.push(err);
  6260. }, value => {
  6261. values.push(value);
  6262. });
  6263. });
  6264. return {
  6265. errors,
  6266. values
  6267. };
  6268. };
  6269. const isInlinePattern = pattern => pattern.type === 'inline-command' || pattern.type === 'inline-format';
  6270. const isBlockPattern = pattern => pattern.type === 'block-command' || pattern.type === 'block-format';
  6271. const normalizePattern = pattern => {
  6272. const err = message => Result.error({
  6273. message,
  6274. pattern
  6275. });
  6276. const formatOrCmd = (name, onFormat, onCommand) => {
  6277. if (pattern.format !== undefined) {
  6278. let formats;
  6279. if (isArray$1(pattern.format)) {
  6280. if (!forall(pattern.format, isString)) {
  6281. return err(name + ' pattern has non-string items in the `format` array');
  6282. }
  6283. formats = pattern.format;
  6284. } else if (isString(pattern.format)) {
  6285. formats = [pattern.format];
  6286. } else {
  6287. return err(name + ' pattern has non-string `format` parameter');
  6288. }
  6289. return Result.value(onFormat(formats));
  6290. } else if (pattern.cmd !== undefined) {
  6291. if (!isString(pattern.cmd)) {
  6292. return err(name + ' pattern has non-string `cmd` parameter');
  6293. }
  6294. return Result.value(onCommand(pattern.cmd, pattern.value));
  6295. } else {
  6296. return err(name + ' pattern is missing both `format` and `cmd` parameters');
  6297. }
  6298. };
  6299. if (!isObject(pattern)) {
  6300. return err('Raw pattern is not an object');
  6301. }
  6302. if (!isString(pattern.start)) {
  6303. return err('Raw pattern is missing `start` parameter');
  6304. }
  6305. if (pattern.end !== undefined) {
  6306. if (!isString(pattern.end)) {
  6307. return err('Inline pattern has non-string `end` parameter');
  6308. }
  6309. if (pattern.start.length === 0 && pattern.end.length === 0) {
  6310. return err('Inline pattern has empty `start` and `end` parameters');
  6311. }
  6312. let start = pattern.start;
  6313. let end = pattern.end;
  6314. if (end.length === 0) {
  6315. end = start;
  6316. start = '';
  6317. }
  6318. return formatOrCmd('Inline', format => ({
  6319. type: 'inline-format',
  6320. start,
  6321. end,
  6322. format
  6323. }), (cmd, value) => ({
  6324. type: 'inline-command',
  6325. start,
  6326. end,
  6327. cmd,
  6328. value
  6329. }));
  6330. } else if (pattern.replacement !== undefined) {
  6331. if (!isString(pattern.replacement)) {
  6332. return err('Replacement pattern has non-string `replacement` parameter');
  6333. }
  6334. if (pattern.start.length === 0) {
  6335. return err('Replacement pattern has empty `start` parameter');
  6336. }
  6337. return Result.value({
  6338. type: 'inline-command',
  6339. start: '',
  6340. end: pattern.start,
  6341. cmd: 'mceInsertContent',
  6342. value: pattern.replacement
  6343. });
  6344. } else {
  6345. if (pattern.start.length === 0) {
  6346. return err('Block pattern has empty `start` parameter');
  6347. }
  6348. return formatOrCmd('Block', formats => ({
  6349. type: 'block-format',
  6350. start: pattern.start,
  6351. format: formats[0]
  6352. }), (command, commandValue) => ({
  6353. type: 'block-command',
  6354. start: pattern.start,
  6355. cmd: command,
  6356. value: commandValue
  6357. }));
  6358. }
  6359. };
  6360. const getBlockPatterns = patterns => filter$5(patterns, isBlockPattern);
  6361. const getInlinePatterns = patterns => filter$5(patterns, isInlinePattern);
  6362. const createPatternSet = (patterns, dynamicPatternsLookup) => ({
  6363. inlinePatterns: getInlinePatterns(patterns),
  6364. blockPatterns: getBlockPatterns(patterns),
  6365. dynamicPatternsLookup
  6366. });
  6367. const fromRawPatterns = patterns => {
  6368. const normalized = partition$1(map$3(patterns, normalizePattern));
  6369. each$e(normalized.errors, err => console.error(err.message, err.pattern));
  6370. return normalized.values;
  6371. };
  6372. const fromRawPatternsLookup = lookupFn => {
  6373. return ctx => {
  6374. const rawPatterns = lookupFn(ctx);
  6375. return fromRawPatterns(rawPatterns);
  6376. };
  6377. };
  6378. const deviceDetection$1 = detect$2().deviceType;
  6379. const isTouch = deviceDetection$1.isTouch();
  6380. const DOM$a = DOMUtils.DOM;
  6381. const getHash = value => {
  6382. const items = value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(',');
  6383. return foldl(items, (output, item) => {
  6384. const arr = item.split('=');
  6385. const key = arr[0];
  6386. const val = arr.length > 1 ? arr[1] : key;
  6387. output[trim$3(key)] = trim$3(val);
  6388. return output;
  6389. }, {});
  6390. };
  6391. const isRegExp = x => is$4(x, RegExp);
  6392. const option = name => editor => editor.options.get(name);
  6393. const stringOrObjectProcessor = value => isString(value) || isObject(value);
  6394. const bodyOptionProcessor = (editor, defaultValue = '') => value => {
  6395. const valid = isString(value);
  6396. if (valid) {
  6397. if (value.indexOf('=') !== -1) {
  6398. const bodyObj = getHash(value);
  6399. return {
  6400. value: get$a(bodyObj, editor.id).getOr(defaultValue),
  6401. valid
  6402. };
  6403. } else {
  6404. return {
  6405. value,
  6406. valid
  6407. };
  6408. }
  6409. } else {
  6410. return {
  6411. valid: false,
  6412. message: 'Must be a string.'
  6413. };
  6414. }
  6415. };
  6416. const register$7 = editor => {
  6417. const registerOption = editor.options.register;
  6418. registerOption('id', {
  6419. processor: 'string',
  6420. default: editor.id
  6421. });
  6422. registerOption('selector', { processor: 'string' });
  6423. registerOption('target', { processor: 'object' });
  6424. registerOption('suffix', { processor: 'string' });
  6425. registerOption('cache_suffix', { processor: 'string' });
  6426. registerOption('base_url', { processor: 'string' });
  6427. registerOption('referrer_policy', {
  6428. processor: 'string',
  6429. default: ''
  6430. });
  6431. registerOption('language_load', {
  6432. processor: 'boolean',
  6433. default: true
  6434. });
  6435. registerOption('inline', {
  6436. processor: 'boolean',
  6437. default: false
  6438. });
  6439. registerOption('iframe_attrs', {
  6440. processor: 'object',
  6441. default: {}
  6442. });
  6443. registerOption('doctype', {
  6444. processor: 'string',
  6445. default: '<!DOCTYPE html>'
  6446. });
  6447. registerOption('document_base_url', {
  6448. processor: 'string',
  6449. default: editor.documentBaseUrl
  6450. });
  6451. registerOption('body_id', {
  6452. processor: bodyOptionProcessor(editor, 'tinymce'),
  6453. default: 'tinymce'
  6454. });
  6455. registerOption('body_class', {
  6456. processor: bodyOptionProcessor(editor),
  6457. default: ''
  6458. });
  6459. registerOption('content_security_policy', {
  6460. processor: 'string',
  6461. default: ''
  6462. });
  6463. registerOption('br_in_pre', {
  6464. processor: 'boolean',
  6465. default: true
  6466. });
  6467. registerOption('forced_root_block', {
  6468. processor: value => {
  6469. const valid = isString(value) && isNotEmpty(value);
  6470. if (valid) {
  6471. return {
  6472. value,
  6473. valid
  6474. };
  6475. } else {
  6476. return {
  6477. valid: false,
  6478. message: 'Must be a non-empty string.'
  6479. };
  6480. }
  6481. },
  6482. default: 'p'
  6483. });
  6484. registerOption('forced_root_block_attrs', {
  6485. processor: 'object',
  6486. default: {}
  6487. });
  6488. registerOption('newline_behavior', {
  6489. processor: value => {
  6490. const valid = contains$2([
  6491. 'block',
  6492. 'linebreak',
  6493. 'invert',
  6494. 'default'
  6495. ], value);
  6496. return valid ? {
  6497. value,
  6498. valid
  6499. } : {
  6500. valid: false,
  6501. message: 'Must be one of: block, linebreak, invert or default.'
  6502. };
  6503. },
  6504. default: 'default'
  6505. });
  6506. registerOption('br_newline_selector', {
  6507. processor: 'string',
  6508. default: '.mce-toc h2,figcaption,caption'
  6509. });
  6510. registerOption('no_newline_selector', {
  6511. processor: 'string',
  6512. default: ''
  6513. });
  6514. registerOption('keep_styles', {
  6515. processor: 'boolean',
  6516. default: true
  6517. });
  6518. registerOption('end_container_on_empty_block', {
  6519. processor: value => {
  6520. if (isBoolean(value)) {
  6521. return {
  6522. valid: true,
  6523. value
  6524. };
  6525. } else if (isString(value)) {
  6526. return {
  6527. valid: true,
  6528. value
  6529. };
  6530. } else {
  6531. return {
  6532. valid: false,
  6533. message: 'Must be boolean or a string'
  6534. };
  6535. }
  6536. },
  6537. default: 'blockquote'
  6538. });
  6539. registerOption('font_size_style_values', {
  6540. processor: 'string',
  6541. default: 'xx-small,x-small,small,medium,large,x-large,xx-large'
  6542. });
  6543. registerOption('font_size_legacy_values', {
  6544. processor: 'string',
  6545. default: 'xx-small,small,medium,large,x-large,xx-large,300%'
  6546. });
  6547. registerOption('font_size_classes', {
  6548. processor: 'string',
  6549. default: ''
  6550. });
  6551. registerOption('automatic_uploads', {
  6552. processor: 'boolean',
  6553. default: true
  6554. });
  6555. registerOption('images_reuse_filename', {
  6556. processor: 'boolean',
  6557. default: false
  6558. });
  6559. registerOption('images_replace_blob_uris', {
  6560. processor: 'boolean',
  6561. default: true
  6562. });
  6563. registerOption('icons', {
  6564. processor: 'string',
  6565. default: ''
  6566. });
  6567. registerOption('icons_url', {
  6568. processor: 'string',
  6569. default: ''
  6570. });
  6571. registerOption('images_upload_url', {
  6572. processor: 'string',
  6573. default: ''
  6574. });
  6575. registerOption('images_upload_base_path', {
  6576. processor: 'string',
  6577. default: ''
  6578. });
  6579. registerOption('images_upload_credentials', {
  6580. processor: 'boolean',
  6581. default: false
  6582. });
  6583. registerOption('images_upload_handler', { processor: 'function' });
  6584. registerOption('language', {
  6585. processor: 'string',
  6586. default: 'en'
  6587. });
  6588. registerOption('language_url', {
  6589. processor: 'string',
  6590. default: ''
  6591. });
  6592. registerOption('entity_encoding', {
  6593. processor: 'string',
  6594. default: 'named'
  6595. });
  6596. registerOption('indent', {
  6597. processor: 'boolean',
  6598. default: true
  6599. });
  6600. registerOption('indent_before', {
  6601. processor: 'string',
  6602. default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
  6603. });
  6604. registerOption('indent_after', {
  6605. processor: 'string',
  6606. default: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' + 'tfoot,tbody,tr,section,summary,article,hgroup,aside,figure,figcaption,option,optgroup,datalist'
  6607. });
  6608. registerOption('indent_use_margin', {
  6609. processor: 'boolean',
  6610. default: false
  6611. });
  6612. registerOption('indentation', {
  6613. processor: 'string',
  6614. default: '40px'
  6615. });
  6616. registerOption('content_css', {
  6617. processor: value => {
  6618. const valid = value === false || isString(value) || isArrayOf(value, isString);
  6619. if (valid) {
  6620. if (isString(value)) {
  6621. return {
  6622. value: map$3(value.split(','), trim$3),
  6623. valid
  6624. };
  6625. } else if (isArray$1(value)) {
  6626. return {
  6627. value,
  6628. valid
  6629. };
  6630. } else if (value === false) {
  6631. return {
  6632. value: [],
  6633. valid
  6634. };
  6635. } else {
  6636. return {
  6637. value,
  6638. valid
  6639. };
  6640. }
  6641. } else {
  6642. return {
  6643. valid: false,
  6644. message: 'Must be false, a string or an array of strings.'
  6645. };
  6646. }
  6647. },
  6648. default: isInline(editor) ? [] : ['default']
  6649. });
  6650. registerOption('content_style', { processor: 'string' });
  6651. registerOption('content_css_cors', {
  6652. processor: 'boolean',
  6653. default: false
  6654. });
  6655. registerOption('font_css', {
  6656. processor: value => {
  6657. const valid = isString(value) || isArrayOf(value, isString);
  6658. if (valid) {
  6659. const newValue = isArray$1(value) ? value : map$3(value.split(','), trim$3);
  6660. return {
  6661. value: newValue,
  6662. valid
  6663. };
  6664. } else {
  6665. return {
  6666. valid: false,
  6667. message: 'Must be a string or an array of strings.'
  6668. };
  6669. }
  6670. },
  6671. default: []
  6672. });
  6673. registerOption('inline_boundaries', {
  6674. processor: 'boolean',
  6675. default: true
  6676. });
  6677. registerOption('inline_boundaries_selector', {
  6678. processor: 'string',
  6679. default: 'a[href],code,span.mce-annotation'
  6680. });
  6681. registerOption('object_resizing', {
  6682. processor: value => {
  6683. const valid = isBoolean(value) || isString(value);
  6684. if (valid) {
  6685. if (value === false || deviceDetection$1.isiPhone() || deviceDetection$1.isiPad()) {
  6686. return {
  6687. value: '',
  6688. valid
  6689. };
  6690. } else {
  6691. return {
  6692. value: value === true ? 'table,img,figure.image,div,video,iframe' : value,
  6693. valid
  6694. };
  6695. }
  6696. } else {
  6697. return {
  6698. valid: false,
  6699. message: 'Must be boolean or a string'
  6700. };
  6701. }
  6702. },
  6703. default: !isTouch
  6704. });
  6705. registerOption('resize_img_proportional', {
  6706. processor: 'boolean',
  6707. default: true
  6708. });
  6709. registerOption('event_root', { processor: 'object' });
  6710. registerOption('service_message', { processor: 'string' });
  6711. registerOption('theme', {
  6712. processor: value => value === false || isString(value) || isFunction(value),
  6713. default: 'silver'
  6714. });
  6715. registerOption('theme_url', { processor: 'string' });
  6716. registerOption('formats', { processor: 'object' });
  6717. registerOption('format_empty_lines', {
  6718. processor: 'boolean',
  6719. default: false
  6720. });
  6721. registerOption('format_noneditable_selector', {
  6722. processor: 'string',
  6723. default: ''
  6724. });
  6725. registerOption('preview_styles', {
  6726. processor: value => {
  6727. const valid = value === false || isString(value);
  6728. if (valid) {
  6729. return {
  6730. value: value === false ? '' : value,
  6731. valid
  6732. };
  6733. } else {
  6734. return {
  6735. valid: false,
  6736. message: 'Must be false or a string'
  6737. };
  6738. }
  6739. },
  6740. default: 'font-family font-size font-weight font-style text-decoration text-transform color background-color border border-radius outline text-shadow'
  6741. });
  6742. registerOption('custom_ui_selector', {
  6743. processor: 'string',
  6744. default: ''
  6745. });
  6746. registerOption('hidden_input', {
  6747. processor: 'boolean',
  6748. default: true
  6749. });
  6750. registerOption('submit_patch', {
  6751. processor: 'boolean',
  6752. default: true
  6753. });
  6754. registerOption('encoding', { processor: 'string' });
  6755. registerOption('add_form_submit_trigger', {
  6756. processor: 'boolean',
  6757. default: true
  6758. });
  6759. registerOption('add_unload_trigger', {
  6760. processor: 'boolean',
  6761. default: true
  6762. });
  6763. registerOption('custom_undo_redo_levels', {
  6764. processor: 'number',
  6765. default: 0
  6766. });
  6767. registerOption('disable_nodechange', {
  6768. processor: 'boolean',
  6769. default: false
  6770. });
  6771. registerOption('readonly', {
  6772. processor: 'boolean',
  6773. default: false
  6774. });
  6775. registerOption('plugins', {
  6776. processor: 'string[]',
  6777. default: []
  6778. });
  6779. registerOption('external_plugins', { processor: 'object' });
  6780. registerOption('forced_plugins', { processor: 'string[]' });
  6781. registerOption('model', {
  6782. processor: 'string',
  6783. default: editor.hasPlugin('rtc') ? 'plugin' : 'dom'
  6784. });
  6785. registerOption('model_url', { processor: 'string' });
  6786. registerOption('block_unsupported_drop', {
  6787. processor: 'boolean',
  6788. default: true
  6789. });
  6790. registerOption('visual', {
  6791. processor: 'boolean',
  6792. default: true
  6793. });
  6794. registerOption('visual_table_class', {
  6795. processor: 'string',
  6796. default: 'mce-item-table'
  6797. });
  6798. registerOption('visual_anchor_class', {
  6799. processor: 'string',
  6800. default: 'mce-item-anchor'
  6801. });
  6802. registerOption('iframe_aria_text', {
  6803. processor: 'string',
  6804. default: 'Rich Text Area. Press ALT-0 for help.'
  6805. });
  6806. registerOption('setup', { processor: 'function' });
  6807. registerOption('init_instance_callback', { processor: 'function' });
  6808. registerOption('url_converter', {
  6809. processor: 'function',
  6810. default: editor.convertURL
  6811. });
  6812. registerOption('url_converter_scope', {
  6813. processor: 'object',
  6814. default: editor
  6815. });
  6816. registerOption('urlconverter_callback', { processor: 'function' });
  6817. registerOption('allow_conditional_comments', {
  6818. processor: 'boolean',
  6819. default: false
  6820. });
  6821. registerOption('allow_html_data_urls', {
  6822. processor: 'boolean',
  6823. default: false
  6824. });
  6825. registerOption('allow_svg_data_urls', { processor: 'boolean' });
  6826. registerOption('allow_html_in_named_anchor', {
  6827. processor: 'boolean',
  6828. default: false
  6829. });
  6830. registerOption('allow_script_urls', {
  6831. processor: 'boolean',
  6832. default: false
  6833. });
  6834. registerOption('allow_unsafe_link_target', {
  6835. processor: 'boolean',
  6836. default: false
  6837. });
  6838. registerOption('convert_fonts_to_spans', {
  6839. processor: 'boolean',
  6840. default: true,
  6841. deprecated: true
  6842. });
  6843. registerOption('fix_list_elements', {
  6844. processor: 'boolean',
  6845. default: false
  6846. });
  6847. registerOption('preserve_cdata', {
  6848. processor: 'boolean',
  6849. default: false
  6850. });
  6851. registerOption('remove_trailing_brs', { processor: 'boolean' });
  6852. registerOption('inline_styles', {
  6853. processor: 'boolean',
  6854. default: true,
  6855. deprecated: true
  6856. });
  6857. registerOption('element_format', {
  6858. processor: 'string',
  6859. default: 'html'
  6860. });
  6861. registerOption('entities', { processor: 'string' });
  6862. registerOption('schema', {
  6863. processor: 'string',
  6864. default: 'html5'
  6865. });
  6866. registerOption('convert_urls', {
  6867. processor: 'boolean',
  6868. default: true
  6869. });
  6870. registerOption('relative_urls', {
  6871. processor: 'boolean',
  6872. default: true
  6873. });
  6874. registerOption('remove_script_host', {
  6875. processor: 'boolean',
  6876. default: true
  6877. });
  6878. registerOption('custom_elements', { processor: 'string' });
  6879. registerOption('extended_valid_elements', { processor: 'string' });
  6880. registerOption('invalid_elements', { processor: 'string' });
  6881. registerOption('invalid_styles', { processor: stringOrObjectProcessor });
  6882. registerOption('valid_children', { processor: 'string' });
  6883. registerOption('valid_classes', { processor: stringOrObjectProcessor });
  6884. registerOption('valid_elements', { processor: 'string' });
  6885. registerOption('valid_styles', { processor: stringOrObjectProcessor });
  6886. registerOption('verify_html', {
  6887. processor: 'boolean',
  6888. default: true
  6889. });
  6890. registerOption('auto_focus', { processor: value => isString(value) || value === true });
  6891. registerOption('browser_spellcheck', {
  6892. processor: 'boolean',
  6893. default: false
  6894. });
  6895. registerOption('protect', { processor: 'array' });
  6896. registerOption('images_file_types', {
  6897. processor: 'string',
  6898. default: 'jpeg,jpg,jpe,jfi,jif,jfif,png,gif,bmp,webp'
  6899. });
  6900. registerOption('deprecation_warnings', {
  6901. processor: 'boolean',
  6902. default: true
  6903. });
  6904. registerOption('a11y_advanced_options', {
  6905. processor: 'boolean',
  6906. default: false
  6907. });
  6908. registerOption('api_key', { processor: 'string' });
  6909. registerOption('paste_block_drop', {
  6910. processor: 'boolean',
  6911. default: false
  6912. });
  6913. registerOption('paste_data_images', {
  6914. processor: 'boolean',
  6915. default: true
  6916. });
  6917. registerOption('paste_preprocess', { processor: 'function' });
  6918. registerOption('paste_postprocess', { processor: 'function' });
  6919. registerOption('paste_webkit_styles', {
  6920. processor: 'string',
  6921. default: 'none'
  6922. });
  6923. registerOption('paste_remove_styles_if_webkit', {
  6924. processor: 'boolean',
  6925. default: true
  6926. });
  6927. registerOption('paste_merge_formats', {
  6928. processor: 'boolean',
  6929. default: true
  6930. });
  6931. registerOption('smart_paste', {
  6932. processor: 'boolean',
  6933. default: true
  6934. });
  6935. registerOption('paste_as_text', {
  6936. processor: 'boolean',
  6937. default: false
  6938. });
  6939. registerOption('paste_tab_spaces', {
  6940. processor: 'number',
  6941. default: 4
  6942. });
  6943. registerOption('text_patterns', {
  6944. processor: value => {
  6945. if (isArrayOf(value, isObject) || value === false) {
  6946. const patterns = value === false ? [] : value;
  6947. return {
  6948. value: fromRawPatterns(patterns),
  6949. valid: true
  6950. };
  6951. } else {
  6952. return {
  6953. valid: false,
  6954. message: 'Must be an array of objects or false.'
  6955. };
  6956. }
  6957. },
  6958. default: [
  6959. {
  6960. start: '*',
  6961. end: '*',
  6962. format: 'italic'
  6963. },
  6964. {
  6965. start: '**',
  6966. end: '**',
  6967. format: 'bold'
  6968. },
  6969. {
  6970. start: '#',
  6971. format: 'h1'
  6972. },
  6973. {
  6974. start: '##',
  6975. format: 'h2'
  6976. },
  6977. {
  6978. start: '###',
  6979. format: 'h3'
  6980. },
  6981. {
  6982. start: '####',
  6983. format: 'h4'
  6984. },
  6985. {
  6986. start: '#####',
  6987. format: 'h5'
  6988. },
  6989. {
  6990. start: '######',
  6991. format: 'h6'
  6992. },
  6993. {
  6994. start: '1. ',
  6995. cmd: 'InsertOrderedList'
  6996. },
  6997. {
  6998. start: '* ',
  6999. cmd: 'InsertUnorderedList'
  7000. },
  7001. {
  7002. start: '- ',
  7003. cmd: 'InsertUnorderedList'
  7004. }
  7005. ]
  7006. });
  7007. registerOption('text_patterns_lookup', {
  7008. processor: value => {
  7009. if (isFunction(value)) {
  7010. return {
  7011. value: fromRawPatternsLookup(value),
  7012. valid: true
  7013. };
  7014. } else {
  7015. return {
  7016. valid: false,
  7017. message: 'Must be a single function'
  7018. };
  7019. }
  7020. },
  7021. default: _ctx => []
  7022. });
  7023. registerOption('noneditable_class', {
  7024. processor: 'string',
  7025. default: 'mceNonEditable'
  7026. });
  7027. registerOption('editable_class', {
  7028. processor: 'string',
  7029. default: 'mceEditable'
  7030. });
  7031. registerOption('noneditable_regexp', {
  7032. processor: value => {
  7033. if (isArrayOf(value, isRegExp)) {
  7034. return {
  7035. value,
  7036. valid: true
  7037. };
  7038. } else if (isRegExp(value)) {
  7039. return {
  7040. value: [value],
  7041. valid: true
  7042. };
  7043. } else {
  7044. return {
  7045. valid: false,
  7046. message: 'Must be a RegExp or an array of RegExp.'
  7047. };
  7048. }
  7049. },
  7050. default: []
  7051. });
  7052. registerOption('table_tab_navigation', {
  7053. processor: 'boolean',
  7054. default: true
  7055. });
  7056. editor.on('ScriptsLoaded', () => {
  7057. registerOption('directionality', {
  7058. processor: 'string',
  7059. default: I18n.isRtl() ? 'rtl' : undefined
  7060. });
  7061. registerOption('placeholder', {
  7062. processor: 'string',
  7063. default: DOM$a.getAttrib(editor.getElement(), 'placeholder')
  7064. });
  7065. });
  7066. };
  7067. const getIframeAttrs = option('iframe_attrs');
  7068. const getDocType = option('doctype');
  7069. const getDocumentBaseUrl = option('document_base_url');
  7070. const getBodyId = option('body_id');
  7071. const getBodyClass = option('body_class');
  7072. const getContentSecurityPolicy = option('content_security_policy');
  7073. const shouldPutBrInPre$1 = option('br_in_pre');
  7074. const getForcedRootBlock = option('forced_root_block');
  7075. const getForcedRootBlockAttrs = option('forced_root_block_attrs');
  7076. const getNewlineBehavior = option('newline_behavior');
  7077. const getBrNewLineSelector = option('br_newline_selector');
  7078. const getNoNewLineSelector = option('no_newline_selector');
  7079. const shouldKeepStyles = option('keep_styles');
  7080. const shouldEndContainerOnEmptyBlock = option('end_container_on_empty_block');
  7081. const isAutomaticUploadsEnabled = option('automatic_uploads');
  7082. const shouldReuseFileName = option('images_reuse_filename');
  7083. const shouldReplaceBlobUris = option('images_replace_blob_uris');
  7084. const getIconPackName = option('icons');
  7085. const getIconsUrl = option('icons_url');
  7086. const getImageUploadUrl = option('images_upload_url');
  7087. const getImageUploadBasePath = option('images_upload_base_path');
  7088. const getImagesUploadCredentials = option('images_upload_credentials');
  7089. const getImagesUploadHandler = option('images_upload_handler');
  7090. const shouldUseContentCssCors = option('content_css_cors');
  7091. const getReferrerPolicy = option('referrer_policy');
  7092. const getLanguageCode = option('language');
  7093. const getLanguageUrl = option('language_url');
  7094. const shouldIndentUseMargin = option('indent_use_margin');
  7095. const getIndentation = option('indentation');
  7096. const getContentCss = option('content_css');
  7097. const getContentStyle = option('content_style');
  7098. const getFontCss = option('font_css');
  7099. const getDirectionality = option('directionality');
  7100. const getInlineBoundarySelector = option('inline_boundaries_selector');
  7101. const getObjectResizing = option('object_resizing');
  7102. const getResizeImgProportional = option('resize_img_proportional');
  7103. const getPlaceholder = option('placeholder');
  7104. const getEventRoot = option('event_root');
  7105. const getServiceMessage = option('service_message');
  7106. const getTheme = option('theme');
  7107. const getThemeUrl = option('theme_url');
  7108. const getModel = option('model');
  7109. const getModelUrl = option('model_url');
  7110. const isInlineBoundariesEnabled = option('inline_boundaries');
  7111. const getFormats = option('formats');
  7112. const getPreviewStyles = option('preview_styles');
  7113. const canFormatEmptyLines = option('format_empty_lines');
  7114. const getFormatNoneditableSelector = option('format_noneditable_selector');
  7115. const getCustomUiSelector = option('custom_ui_selector');
  7116. const isInline = option('inline');
  7117. const hasHiddenInput = option('hidden_input');
  7118. const shouldPatchSubmit = option('submit_patch');
  7119. const shouldAddFormSubmitTrigger = option('add_form_submit_trigger');
  7120. const shouldAddUnloadTrigger = option('add_unload_trigger');
  7121. const getCustomUndoRedoLevels = option('custom_undo_redo_levels');
  7122. const shouldDisableNodeChange = option('disable_nodechange');
  7123. const isReadOnly$1 = option('readonly');
  7124. const hasContentCssCors = option('content_css_cors');
  7125. const getPlugins = option('plugins');
  7126. const getExternalPlugins$1 = option('external_plugins');
  7127. const shouldBlockUnsupportedDrop = option('block_unsupported_drop');
  7128. const isVisualAidsEnabled = option('visual');
  7129. const getVisualAidsTableClass = option('visual_table_class');
  7130. const getVisualAidsAnchorClass = option('visual_anchor_class');
  7131. const getIframeAriaText = option('iframe_aria_text');
  7132. const getSetupCallback = option('setup');
  7133. const getInitInstanceCallback = option('init_instance_callback');
  7134. const getUrlConverterCallback = option('urlconverter_callback');
  7135. const getAutoFocus = option('auto_focus');
  7136. const shouldBrowserSpellcheck = option('browser_spellcheck');
  7137. const getProtect = option('protect');
  7138. const shouldPasteBlockDrop = option('paste_block_drop');
  7139. const shouldPasteDataImages = option('paste_data_images');
  7140. const getPastePreProcess = option('paste_preprocess');
  7141. const getPastePostProcess = option('paste_postprocess');
  7142. const getPasteWebkitStyles = option('paste_webkit_styles');
  7143. const shouldPasteRemoveWebKitStyles = option('paste_remove_styles_if_webkit');
  7144. const shouldPasteMergeFormats = option('paste_merge_formats');
  7145. const isSmartPasteEnabled = option('smart_paste');
  7146. const isPasteAsTextEnabled = option('paste_as_text');
  7147. const getPasteTabSpaces = option('paste_tab_spaces');
  7148. const shouldAllowHtmlDataUrls = option('allow_html_data_urls');
  7149. const getTextPatterns = option('text_patterns');
  7150. const getTextPatternsLookup = option('text_patterns_lookup');
  7151. const getNonEditableClass = option('noneditable_class');
  7152. const getEditableClass = option('editable_class');
  7153. const getNonEditableRegExps = option('noneditable_regexp');
  7154. const shouldPreserveCData = option('preserve_cdata');
  7155. const hasTextPatternsLookup = editor => editor.options.isSet('text_patterns_lookup');
  7156. const getFontStyleValues = editor => Tools.explode(editor.options.get('font_size_style_values'));
  7157. const getFontSizeClasses = editor => Tools.explode(editor.options.get('font_size_classes'));
  7158. const isEncodingXml = editor => editor.options.get('encoding') === 'xml';
  7159. const getAllowedImageFileTypes = editor => Tools.explode(editor.options.get('images_file_types'));
  7160. const hasTableTabNavigation = option('table_tab_navigation');
  7161. const isElement$3 = isElement$6;
  7162. const isText$5 = isText$a;
  7163. const removeNode$1 = node => {
  7164. const parentNode = node.parentNode;
  7165. if (parentNode) {
  7166. parentNode.removeChild(node);
  7167. }
  7168. };
  7169. const trimCount = text => {
  7170. const trimmedText = trim$1(text);
  7171. return {
  7172. count: text.length - trimmedText.length,
  7173. text: trimmedText
  7174. };
  7175. };
  7176. const deleteZwspChars = caretContainer => {
  7177. let idx;
  7178. while ((idx = caretContainer.data.lastIndexOf(ZWSP$1)) !== -1) {
  7179. caretContainer.deleteData(idx, 1);
  7180. }
  7181. };
  7182. const removeUnchanged = (caretContainer, pos) => {
  7183. remove$4(caretContainer);
  7184. return pos;
  7185. };
  7186. const removeTextAndReposition = (caretContainer, pos) => {
  7187. const before = trimCount(caretContainer.data.substr(0, pos.offset()));
  7188. const after = trimCount(caretContainer.data.substr(pos.offset()));
  7189. const text = before.text + after.text;
  7190. if (text.length > 0) {
  7191. deleteZwspChars(caretContainer);
  7192. return CaretPosition(caretContainer, pos.offset() - before.count);
  7193. } else {
  7194. return pos;
  7195. }
  7196. };
  7197. const removeElementAndReposition = (caretContainer, pos) => {
  7198. const parentNode = pos.container();
  7199. const newPosition = indexOf$1(from(parentNode.childNodes), caretContainer).map(index => {
  7200. return index < pos.offset() ? CaretPosition(parentNode, pos.offset() - 1) : pos;
  7201. }).getOr(pos);
  7202. remove$4(caretContainer);
  7203. return newPosition;
  7204. };
  7205. const removeTextCaretContainer = (caretContainer, pos) => isText$5(caretContainer) && pos.container() === caretContainer ? removeTextAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
  7206. const removeElementCaretContainer = (caretContainer, pos) => pos.container() === caretContainer.parentNode ? removeElementAndReposition(caretContainer, pos) : removeUnchanged(caretContainer, pos);
  7207. const removeAndReposition = (container, pos) => CaretPosition.isTextPosition(pos) ? removeTextCaretContainer(container, pos) : removeElementCaretContainer(container, pos);
  7208. const remove$4 = caretContainerNode => {
  7209. if (isElement$3(caretContainerNode) && isCaretContainer$2(caretContainerNode)) {
  7210. if (hasContent(caretContainerNode)) {
  7211. caretContainerNode.removeAttribute('data-mce-caret');
  7212. } else {
  7213. removeNode$1(caretContainerNode);
  7214. }
  7215. }
  7216. if (isText$5(caretContainerNode)) {
  7217. deleteZwspChars(caretContainerNode);
  7218. if (caretContainerNode.data.length === 0) {
  7219. removeNode$1(caretContainerNode);
  7220. }
  7221. }
  7222. };
  7223. const isContentEditableFalse$7 = isContentEditableFalse$a;
  7224. const isMedia$1 = isMedia$2;
  7225. const isTableCell$1 = isTableCell$3;
  7226. const inlineFakeCaretSelector = '*[contentEditable=false],video,audio,embed,object';
  7227. const getAbsoluteClientRect = (root, element, before) => {
  7228. const clientRect = collapse(element.getBoundingClientRect(), before);
  7229. let scrollX;
  7230. let scrollY;
  7231. if (root.tagName === 'BODY') {
  7232. const docElm = root.ownerDocument.documentElement;
  7233. scrollX = root.scrollLeft || docElm.scrollLeft;
  7234. scrollY = root.scrollTop || docElm.scrollTop;
  7235. } else {
  7236. const rootRect = root.getBoundingClientRect();
  7237. scrollX = root.scrollLeft - rootRect.left;
  7238. scrollY = root.scrollTop - rootRect.top;
  7239. }
  7240. clientRect.left += scrollX;
  7241. clientRect.right += scrollX;
  7242. clientRect.top += scrollY;
  7243. clientRect.bottom += scrollY;
  7244. clientRect.width = 1;
  7245. let margin = element.offsetWidth - element.clientWidth;
  7246. if (margin > 0) {
  7247. if (before) {
  7248. margin *= -1;
  7249. }
  7250. clientRect.left += margin;
  7251. clientRect.right += margin;
  7252. }
  7253. return clientRect;
  7254. };
  7255. const trimInlineCaretContainers = root => {
  7256. var _a, _b;
  7257. const fakeCaretTargetNodes = descendants(SugarElement.fromDom(root), inlineFakeCaretSelector);
  7258. for (let i = 0; i < fakeCaretTargetNodes.length; i++) {
  7259. const node = fakeCaretTargetNodes[i].dom;
  7260. let sibling = node.previousSibling;
  7261. if (endsWithCaretContainer$1(sibling)) {
  7262. const data = sibling.data;
  7263. if (data.length === 1) {
  7264. (_a = sibling.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(sibling);
  7265. } else {
  7266. sibling.deleteData(data.length - 1, 1);
  7267. }
  7268. }
  7269. sibling = node.nextSibling;
  7270. if (startsWithCaretContainer$1(sibling)) {
  7271. const data = sibling.data;
  7272. if (data.length === 1) {
  7273. (_b = sibling.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(sibling);
  7274. } else {
  7275. sibling.deleteData(0, 1);
  7276. }
  7277. }
  7278. }
  7279. };
  7280. const FakeCaret = (editor, root, isBlock, hasFocus) => {
  7281. const lastVisualCaret = value$2();
  7282. let cursorInterval;
  7283. let caretContainerNode;
  7284. const caretBlock = getForcedRootBlock(editor);
  7285. const dom = editor.dom;
  7286. const show = (before, element) => {
  7287. let rng;
  7288. hide();
  7289. if (isTableCell$1(element)) {
  7290. return null;
  7291. }
  7292. if (isBlock(element)) {
  7293. const caretContainer = insertBlock(caretBlock, element, before);
  7294. const clientRect = getAbsoluteClientRect(root, element, before);
  7295. dom.setStyle(caretContainer, 'top', clientRect.top);
  7296. caretContainerNode = caretContainer;
  7297. const caret = dom.create('div', {
  7298. 'class': 'mce-visual-caret',
  7299. 'data-mce-bogus': 'all'
  7300. });
  7301. dom.setStyles(caret, { ...clientRect });
  7302. dom.add(root, caret);
  7303. lastVisualCaret.set({
  7304. caret,
  7305. element,
  7306. before
  7307. });
  7308. if (before) {
  7309. dom.addClass(caret, 'mce-visual-caret-before');
  7310. }
  7311. startBlink();
  7312. rng = element.ownerDocument.createRange();
  7313. rng.setStart(caretContainer, 0);
  7314. rng.setEnd(caretContainer, 0);
  7315. } else {
  7316. caretContainerNode = insertInline$1(element, before);
  7317. rng = element.ownerDocument.createRange();
  7318. if (isInlineFakeCaretTarget(caretContainerNode.nextSibling)) {
  7319. rng.setStart(caretContainerNode, 0);
  7320. rng.setEnd(caretContainerNode, 0);
  7321. } else {
  7322. rng.setStart(caretContainerNode, 1);
  7323. rng.setEnd(caretContainerNode, 1);
  7324. }
  7325. return rng;
  7326. }
  7327. return rng;
  7328. };
  7329. const hide = () => {
  7330. trimInlineCaretContainers(root);
  7331. if (caretContainerNode) {
  7332. remove$4(caretContainerNode);
  7333. caretContainerNode = null;
  7334. }
  7335. lastVisualCaret.on(caretState => {
  7336. dom.remove(caretState.caret);
  7337. lastVisualCaret.clear();
  7338. });
  7339. if (cursorInterval) {
  7340. clearInterval(cursorInterval);
  7341. cursorInterval = undefined;
  7342. }
  7343. };
  7344. const startBlink = () => {
  7345. cursorInterval = setInterval(() => {
  7346. lastVisualCaret.on(caretState => {
  7347. if (hasFocus()) {
  7348. dom.toggleClass(caretState.caret, 'mce-visual-caret-hidden');
  7349. } else {
  7350. dom.addClass(caretState.caret, 'mce-visual-caret-hidden');
  7351. }
  7352. });
  7353. }, 500);
  7354. };
  7355. const reposition = () => {
  7356. lastVisualCaret.on(caretState => {
  7357. const clientRect = getAbsoluteClientRect(root, caretState.element, caretState.before);
  7358. dom.setStyles(caretState.caret, { ...clientRect });
  7359. });
  7360. };
  7361. const destroy = () => clearInterval(cursorInterval);
  7362. const getCss = () => '.mce-visual-caret {' + 'position: absolute;' + 'background-color: black;' + 'background-color: currentcolor;' + '}' + '.mce-visual-caret-hidden {' + 'display: none;' + '}' + '*[data-mce-caret] {' + 'position: absolute;' + 'left: -1000px;' + 'right: auto;' + 'top: 0;' + 'margin: 0;' + 'padding: 0;' + '}';
  7363. return {
  7364. show,
  7365. hide,
  7366. getCss,
  7367. reposition,
  7368. destroy
  7369. };
  7370. };
  7371. const isFakeCaretTableBrowser = () => Env.browser.isFirefox();
  7372. const isInlineFakeCaretTarget = node => isContentEditableFalse$7(node) || isMedia$1(node);
  7373. const isFakeCaretTarget = node => isInlineFakeCaretTarget(node) || isTable$2(node) && isFakeCaretTableBrowser();
  7374. const isContentEditableTrue$1 = isContentEditableTrue$3;
  7375. const isContentEditableFalse$6 = isContentEditableFalse$a;
  7376. const isMedia = isMedia$2;
  7377. const isBlockLike = matchStyleValues('display', 'block table table-cell table-caption list-item');
  7378. const isCaretContainer = isCaretContainer$2;
  7379. const isCaretContainerBlock = isCaretContainerBlock$1;
  7380. const isElement$2 = isElement$6;
  7381. const isText$4 = isText$a;
  7382. const isCaretCandidate$1 = isCaretCandidate$3;
  7383. const isForwards = direction => direction > 0;
  7384. const isBackwards = direction => direction < 0;
  7385. const skipCaretContainers = (walk, shallow) => {
  7386. let node;
  7387. while (node = walk(shallow)) {
  7388. if (!isCaretContainerBlock(node)) {
  7389. return node;
  7390. }
  7391. }
  7392. return null;
  7393. };
  7394. const findNode = (node, direction, predicateFn, rootNode, shallow) => {
  7395. const walker = new DomTreeWalker(node, rootNode);
  7396. const isCefOrCaretContainer = isContentEditableFalse$6(node) || isCaretContainerBlock(node);
  7397. let tempNode;
  7398. if (isBackwards(direction)) {
  7399. if (isCefOrCaretContainer) {
  7400. tempNode = skipCaretContainers(walker.prev.bind(walker), true);
  7401. if (predicateFn(tempNode)) {
  7402. return tempNode;
  7403. }
  7404. }
  7405. while (tempNode = skipCaretContainers(walker.prev.bind(walker), shallow)) {
  7406. if (predicateFn(tempNode)) {
  7407. return tempNode;
  7408. }
  7409. }
  7410. }
  7411. if (isForwards(direction)) {
  7412. if (isCefOrCaretContainer) {
  7413. tempNode = skipCaretContainers(walker.next.bind(walker), true);
  7414. if (predicateFn(tempNode)) {
  7415. return tempNode;
  7416. }
  7417. }
  7418. while (tempNode = skipCaretContainers(walker.next.bind(walker), shallow)) {
  7419. if (predicateFn(tempNode)) {
  7420. return tempNode;
  7421. }
  7422. }
  7423. }
  7424. return null;
  7425. };
  7426. const getEditingHost = (node, rootNode) => {
  7427. const isCETrue = node => isContentEditableTrue$1(node.dom);
  7428. const isRoot = node => node.dom === rootNode;
  7429. return ancestor$3(SugarElement.fromDom(node), isCETrue, isRoot).map(elm => elm.dom).getOr(rootNode);
  7430. };
  7431. const getParentBlock$3 = (node, rootNode) => {
  7432. while (node && node !== rootNode) {
  7433. if (isBlockLike(node)) {
  7434. return node;
  7435. }
  7436. node = node.parentNode;
  7437. }
  7438. return null;
  7439. };
  7440. const isInSameBlock = (caretPosition1, caretPosition2, rootNode) => getParentBlock$3(caretPosition1.container(), rootNode) === getParentBlock$3(caretPosition2.container(), rootNode);
  7441. const getChildNodeAtRelativeOffset = (relativeOffset, caretPosition) => {
  7442. if (!caretPosition) {
  7443. return Optional.none();
  7444. }
  7445. const container = caretPosition.container();
  7446. const offset = caretPosition.offset();
  7447. if (!isElement$2(container)) {
  7448. return Optional.none();
  7449. }
  7450. return Optional.from(container.childNodes[offset + relativeOffset]);
  7451. };
  7452. const beforeAfter = (before, node) => {
  7453. var _a;
  7454. const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
  7455. const range = doc.createRange();
  7456. if (before) {
  7457. range.setStartBefore(node);
  7458. range.setEndBefore(node);
  7459. } else {
  7460. range.setStartAfter(node);
  7461. range.setEndAfter(node);
  7462. }
  7463. return range;
  7464. };
  7465. const isNodesInSameBlock = (root, node1, node2) => getParentBlock$3(node1, root) === getParentBlock$3(node2, root);
  7466. const lean = (left, root, node) => {
  7467. const siblingName = left ? 'previousSibling' : 'nextSibling';
  7468. let tempNode = node;
  7469. while (tempNode && tempNode !== root) {
  7470. let sibling = tempNode[siblingName];
  7471. if (sibling && isCaretContainer(sibling)) {
  7472. sibling = sibling[siblingName];
  7473. }
  7474. if (isContentEditableFalse$6(sibling) || isMedia(sibling)) {
  7475. if (isNodesInSameBlock(root, sibling, tempNode)) {
  7476. return sibling;
  7477. }
  7478. break;
  7479. }
  7480. if (isCaretCandidate$1(sibling)) {
  7481. break;
  7482. }
  7483. tempNode = tempNode.parentNode;
  7484. }
  7485. return null;
  7486. };
  7487. const before$2 = curry(beforeAfter, true);
  7488. const after$2 = curry(beforeAfter, false);
  7489. const normalizeRange = (direction, root, range) => {
  7490. let node;
  7491. const leanLeft = curry(lean, true, root);
  7492. const leanRight = curry(lean, false, root);
  7493. const container = range.startContainer;
  7494. const offset = range.startOffset;
  7495. if (isCaretContainerBlock$1(container)) {
  7496. const block = isText$4(container) ? container.parentNode : container;
  7497. const location = block.getAttribute('data-mce-caret');
  7498. if (location === 'before') {
  7499. node = block.nextSibling;
  7500. if (isFakeCaretTarget(node)) {
  7501. return before$2(node);
  7502. }
  7503. }
  7504. if (location === 'after') {
  7505. node = block.previousSibling;
  7506. if (isFakeCaretTarget(node)) {
  7507. return after$2(node);
  7508. }
  7509. }
  7510. }
  7511. if (!range.collapsed) {
  7512. return range;
  7513. }
  7514. if (isText$a(container)) {
  7515. if (isCaretContainer(container)) {
  7516. if (direction === 1) {
  7517. node = leanRight(container);
  7518. if (node) {
  7519. return before$2(node);
  7520. }
  7521. node = leanLeft(container);
  7522. if (node) {
  7523. return after$2(node);
  7524. }
  7525. }
  7526. if (direction === -1) {
  7527. node = leanLeft(container);
  7528. if (node) {
  7529. return after$2(node);
  7530. }
  7531. node = leanRight(container);
  7532. if (node) {
  7533. return before$2(node);
  7534. }
  7535. }
  7536. return range;
  7537. }
  7538. if (endsWithCaretContainer$1(container) && offset >= container.data.length - 1) {
  7539. if (direction === 1) {
  7540. node = leanRight(container);
  7541. if (node) {
  7542. return before$2(node);
  7543. }
  7544. }
  7545. return range;
  7546. }
  7547. if (startsWithCaretContainer$1(container) && offset <= 1) {
  7548. if (direction === -1) {
  7549. node = leanLeft(container);
  7550. if (node) {
  7551. return after$2(node);
  7552. }
  7553. }
  7554. return range;
  7555. }
  7556. if (offset === container.data.length) {
  7557. node = leanRight(container);
  7558. if (node) {
  7559. return before$2(node);
  7560. }
  7561. return range;
  7562. }
  7563. if (offset === 0) {
  7564. node = leanLeft(container);
  7565. if (node) {
  7566. return after$2(node);
  7567. }
  7568. return range;
  7569. }
  7570. }
  7571. return range;
  7572. };
  7573. const getRelativeCefElm = (forward, caretPosition) => getChildNodeAtRelativeOffset(forward ? 0 : -1, caretPosition).filter(isContentEditableFalse$6);
  7574. const getNormalizedRangeEndPoint = (direction, root, range) => {
  7575. const normalizedRange = normalizeRange(direction, root, range);
  7576. return direction === -1 ? CaretPosition.fromRangeStart(normalizedRange) : CaretPosition.fromRangeEnd(normalizedRange);
  7577. };
  7578. const getElementFromPosition = pos => Optional.from(pos.getNode()).map(SugarElement.fromDom);
  7579. const getElementFromPrevPosition = pos => Optional.from(pos.getNode(true)).map(SugarElement.fromDom);
  7580. const getVisualCaretPosition = (walkFn, caretPosition) => {
  7581. let pos = caretPosition;
  7582. while (pos = walkFn(pos)) {
  7583. if (pos.isVisible()) {
  7584. return pos;
  7585. }
  7586. }
  7587. return pos;
  7588. };
  7589. const isMoveInsideSameBlock = (from, to) => {
  7590. const inSameBlock = isInSameBlock(from, to);
  7591. if (!inSameBlock && isBr$6(from.getNode())) {
  7592. return true;
  7593. }
  7594. return inSameBlock;
  7595. };
  7596. var HDirection;
  7597. (function (HDirection) {
  7598. HDirection[HDirection['Backwards'] = -1] = 'Backwards';
  7599. HDirection[HDirection['Forwards'] = 1] = 'Forwards';
  7600. }(HDirection || (HDirection = {})));
  7601. const isContentEditableFalse$5 = isContentEditableFalse$a;
  7602. const isText$3 = isText$a;
  7603. const isElement$1 = isElement$6;
  7604. const isBr$2 = isBr$6;
  7605. const isCaretCandidate = isCaretCandidate$3;
  7606. const isAtomic = isAtomic$1;
  7607. const isEditableCaretCandidate = isEditableCaretCandidate$1;
  7608. const getParents$3 = (node, root) => {
  7609. const parents = [];
  7610. let tempNode = node;
  7611. while (tempNode && tempNode !== root) {
  7612. parents.push(tempNode);
  7613. tempNode = tempNode.parentNode;
  7614. }
  7615. return parents;
  7616. };
  7617. const nodeAtIndex = (container, offset) => {
  7618. if (container.hasChildNodes() && offset < container.childNodes.length) {
  7619. return container.childNodes[offset];
  7620. }
  7621. return null;
  7622. };
  7623. const getCaretCandidatePosition = (direction, node) => {
  7624. if (isForwards(direction)) {
  7625. if (isCaretCandidate(node.previousSibling) && !isText$3(node.previousSibling)) {
  7626. return CaretPosition.before(node);
  7627. }
  7628. if (isText$3(node)) {
  7629. return CaretPosition(node, 0);
  7630. }
  7631. }
  7632. if (isBackwards(direction)) {
  7633. if (isCaretCandidate(node.nextSibling) && !isText$3(node.nextSibling)) {
  7634. return CaretPosition.after(node);
  7635. }
  7636. if (isText$3(node)) {
  7637. return CaretPosition(node, node.data.length);
  7638. }
  7639. }
  7640. if (isBackwards(direction)) {
  7641. if (isBr$2(node)) {
  7642. return CaretPosition.before(node);
  7643. }
  7644. return CaretPosition.after(node);
  7645. }
  7646. return CaretPosition.before(node);
  7647. };
  7648. const moveForwardFromBr = (root, nextNode) => {
  7649. const nextSibling = nextNode.nextSibling;
  7650. if (nextSibling && isCaretCandidate(nextSibling)) {
  7651. if (isText$3(nextSibling)) {
  7652. return CaretPosition(nextSibling, 0);
  7653. } else {
  7654. return CaretPosition.before(nextSibling);
  7655. }
  7656. } else {
  7657. return findCaretPosition$1(HDirection.Forwards, CaretPosition.after(nextNode), root);
  7658. }
  7659. };
  7660. const findCaretPosition$1 = (direction, startPos, root) => {
  7661. let node;
  7662. let nextNode;
  7663. let innerNode;
  7664. let caretPosition;
  7665. if (!isElement$1(root) || !startPos) {
  7666. return null;
  7667. }
  7668. if (startPos.isEqual(CaretPosition.after(root)) && root.lastChild) {
  7669. caretPosition = CaretPosition.after(root.lastChild);
  7670. if (isBackwards(direction) && isCaretCandidate(root.lastChild) && isElement$1(root.lastChild)) {
  7671. return isBr$2(root.lastChild) ? CaretPosition.before(root.lastChild) : caretPosition;
  7672. }
  7673. } else {
  7674. caretPosition = startPos;
  7675. }
  7676. const container = caretPosition.container();
  7677. let offset = caretPosition.offset();
  7678. if (isText$3(container)) {
  7679. if (isBackwards(direction) && offset > 0) {
  7680. return CaretPosition(container, --offset);
  7681. }
  7682. if (isForwards(direction) && offset < container.length) {
  7683. return CaretPosition(container, ++offset);
  7684. }
  7685. node = container;
  7686. } else {
  7687. if (isBackwards(direction) && offset > 0) {
  7688. nextNode = nodeAtIndex(container, offset - 1);
  7689. if (isCaretCandidate(nextNode)) {
  7690. if (!isAtomic(nextNode)) {
  7691. innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
  7692. if (innerNode) {
  7693. if (isText$3(innerNode)) {
  7694. return CaretPosition(innerNode, innerNode.data.length);
  7695. }
  7696. return CaretPosition.after(innerNode);
  7697. }
  7698. }
  7699. if (isText$3(nextNode)) {
  7700. return CaretPosition(nextNode, nextNode.data.length);
  7701. }
  7702. return CaretPosition.before(nextNode);
  7703. }
  7704. }
  7705. if (isForwards(direction) && offset < container.childNodes.length) {
  7706. nextNode = nodeAtIndex(container, offset);
  7707. if (isCaretCandidate(nextNode)) {
  7708. if (isBr$2(nextNode)) {
  7709. return moveForwardFromBr(root, nextNode);
  7710. }
  7711. if (!isAtomic(nextNode)) {
  7712. innerNode = findNode(nextNode, direction, isEditableCaretCandidate, nextNode);
  7713. if (innerNode) {
  7714. if (isText$3(innerNode)) {
  7715. return CaretPosition(innerNode, 0);
  7716. }
  7717. return CaretPosition.before(innerNode);
  7718. }
  7719. }
  7720. if (isText$3(nextNode)) {
  7721. return CaretPosition(nextNode, 0);
  7722. }
  7723. return CaretPosition.after(nextNode);
  7724. }
  7725. }
  7726. node = nextNode ? nextNode : caretPosition.getNode();
  7727. }
  7728. if (node && (isForwards(direction) && caretPosition.isAtEnd() || isBackwards(direction) && caretPosition.isAtStart())) {
  7729. node = findNode(node, direction, always, root, true);
  7730. if (isEditableCaretCandidate(node, root)) {
  7731. return getCaretCandidatePosition(direction, node);
  7732. }
  7733. }
  7734. nextNode = node ? findNode(node, direction, isEditableCaretCandidate, root) : node;
  7735. const rootContentEditableFalseElm = last$2(filter$5(getParents$3(container, root), isContentEditableFalse$5));
  7736. if (rootContentEditableFalseElm && (!nextNode || !rootContentEditableFalseElm.contains(nextNode))) {
  7737. if (isForwards(direction)) {
  7738. caretPosition = CaretPosition.after(rootContentEditableFalseElm);
  7739. } else {
  7740. caretPosition = CaretPosition.before(rootContentEditableFalseElm);
  7741. }
  7742. return caretPosition;
  7743. }
  7744. if (nextNode) {
  7745. return getCaretCandidatePosition(direction, nextNode);
  7746. }
  7747. return null;
  7748. };
  7749. const CaretWalker = root => ({
  7750. next: caretPosition => {
  7751. return findCaretPosition$1(HDirection.Forwards, caretPosition, root);
  7752. },
  7753. prev: caretPosition => {
  7754. return findCaretPosition$1(HDirection.Backwards, caretPosition, root);
  7755. }
  7756. });
  7757. const walkToPositionIn = (forward, root, start) => {
  7758. const position = forward ? CaretPosition.before(start) : CaretPosition.after(start);
  7759. return fromPosition(forward, root, position);
  7760. };
  7761. const afterElement = node => isBr$6(node) ? CaretPosition.before(node) : CaretPosition.after(node);
  7762. const isBeforeOrStart = position => {
  7763. if (CaretPosition.isTextPosition(position)) {
  7764. return position.offset() === 0;
  7765. } else {
  7766. return isCaretCandidate$3(position.getNode());
  7767. }
  7768. };
  7769. const isAfterOrEnd = position => {
  7770. if (CaretPosition.isTextPosition(position)) {
  7771. const container = position.container();
  7772. return position.offset() === container.data.length;
  7773. } else {
  7774. return isCaretCandidate$3(position.getNode(true));
  7775. }
  7776. };
  7777. const isBeforeAfterSameElement = (from, to) => !CaretPosition.isTextPosition(from) && !CaretPosition.isTextPosition(to) && from.getNode() === to.getNode(true);
  7778. const isAtBr = position => !CaretPosition.isTextPosition(position) && isBr$6(position.getNode());
  7779. const shouldSkipPosition = (forward, from, to) => {
  7780. if (forward) {
  7781. return !isBeforeAfterSameElement(from, to) && !isAtBr(from) && isAfterOrEnd(from) && isBeforeOrStart(to);
  7782. } else {
  7783. return !isBeforeAfterSameElement(to, from) && isBeforeOrStart(from) && isAfterOrEnd(to);
  7784. }
  7785. };
  7786. const fromPosition = (forward, root, pos) => {
  7787. const walker = CaretWalker(root);
  7788. return Optional.from(forward ? walker.next(pos) : walker.prev(pos));
  7789. };
  7790. const navigate = (forward, root, from) => fromPosition(forward, root, from).bind(to => {
  7791. if (isInSameBlock(from, to, root) && shouldSkipPosition(forward, from, to)) {
  7792. return fromPosition(forward, root, to);
  7793. } else {
  7794. return Optional.some(to);
  7795. }
  7796. });
  7797. const navigateIgnore = (forward, root, from, ignoreFilter) => navigate(forward, root, from).bind(pos => ignoreFilter(pos) ? navigateIgnore(forward, root, pos, ignoreFilter) : Optional.some(pos));
  7798. const positionIn = (forward, element) => {
  7799. const startNode = forward ? element.firstChild : element.lastChild;
  7800. if (isText$a(startNode)) {
  7801. return Optional.some(CaretPosition(startNode, forward ? 0 : startNode.data.length));
  7802. } else if (startNode) {
  7803. if (isCaretCandidate$3(startNode)) {
  7804. return Optional.some(forward ? CaretPosition.before(startNode) : afterElement(startNode));
  7805. } else {
  7806. return walkToPositionIn(forward, element, startNode);
  7807. }
  7808. } else {
  7809. return Optional.none();
  7810. }
  7811. };
  7812. const nextPosition = curry(fromPosition, true);
  7813. const prevPosition = curry(fromPosition, false);
  7814. const firstPositionIn = curry(positionIn, true);
  7815. const lastPositionIn = curry(positionIn, false);
  7816. const CARET_ID = '_mce_caret';
  7817. const isCaretNode = node => isElement$6(node) && node.id === CARET_ID;
  7818. const getParentCaretContainer = (body, node) => {
  7819. let currentNode = node;
  7820. while (currentNode && currentNode !== body) {
  7821. if (isCaretNode(currentNode)) {
  7822. return currentNode;
  7823. }
  7824. currentNode = currentNode.parentNode;
  7825. }
  7826. return null;
  7827. };
  7828. const isStringPathBookmark = bookmark => isString(bookmark.start);
  7829. const isRangeBookmark = bookmark => has$2(bookmark, 'rng');
  7830. const isIdBookmark = bookmark => has$2(bookmark, 'id');
  7831. const isIndexBookmark = bookmark => has$2(bookmark, 'name');
  7832. const isPathBookmark = bookmark => Tools.isArray(bookmark.start);
  7833. const isForwardBookmark = bookmark => !isIndexBookmark(bookmark) && isBoolean(bookmark.forward) ? bookmark.forward : true;
  7834. const addBogus = (dom, node) => {
  7835. if (isElement$6(node) && dom.isBlock(node) && !node.innerHTML) {
  7836. node.innerHTML = '<br data-mce-bogus="1" />';
  7837. }
  7838. return node;
  7839. };
  7840. const resolveCaretPositionBookmark = (dom, bookmark) => {
  7841. const startPos = Optional.from(resolve$1(dom.getRoot(), bookmark.start));
  7842. const endPos = Optional.from(resolve$1(dom.getRoot(), bookmark.end));
  7843. return lift2(startPos, endPos, (start, end) => {
  7844. const range = dom.createRng();
  7845. range.setStart(start.container(), start.offset());
  7846. range.setEnd(end.container(), end.offset());
  7847. return {
  7848. range,
  7849. forward: isForwardBookmark(bookmark)
  7850. };
  7851. });
  7852. };
  7853. const insertZwsp = (node, rng) => {
  7854. var _a;
  7855. const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
  7856. const textNode = doc.createTextNode(ZWSP$1);
  7857. node.appendChild(textNode);
  7858. rng.setStart(textNode, 0);
  7859. rng.setEnd(textNode, 0);
  7860. };
  7861. const isEmpty$1 = node => !node.hasChildNodes();
  7862. const tryFindRangePosition = (node, rng) => lastPositionIn(node).fold(never, pos => {
  7863. rng.setStart(pos.container(), pos.offset());
  7864. rng.setEnd(pos.container(), pos.offset());
  7865. return true;
  7866. });
  7867. const padEmptyCaretContainer = (root, node, rng) => {
  7868. if (isEmpty$1(node) && getParentCaretContainer(root, node)) {
  7869. insertZwsp(node, rng);
  7870. return true;
  7871. } else {
  7872. return false;
  7873. }
  7874. };
  7875. const setEndPoint = (dom, start, bookmark, rng) => {
  7876. const point = bookmark[start ? 'start' : 'end'];
  7877. const root = dom.getRoot();
  7878. if (point) {
  7879. let node = root;
  7880. let offset = point[0];
  7881. for (let i = point.length - 1; node && i >= 1; i--) {
  7882. const children = node.childNodes;
  7883. if (padEmptyCaretContainer(root, node, rng)) {
  7884. return true;
  7885. }
  7886. if (point[i] > children.length - 1) {
  7887. if (padEmptyCaretContainer(root, node, rng)) {
  7888. return true;
  7889. }
  7890. return tryFindRangePosition(node, rng);
  7891. }
  7892. node = children[point[i]];
  7893. }
  7894. if (isText$a(node)) {
  7895. offset = Math.min(point[0], node.data.length);
  7896. }
  7897. if (isElement$6(node)) {
  7898. offset = Math.min(point[0], node.childNodes.length);
  7899. }
  7900. if (start) {
  7901. rng.setStart(node, offset);
  7902. } else {
  7903. rng.setEnd(node, offset);
  7904. }
  7905. }
  7906. return true;
  7907. };
  7908. const isValidTextNode = node => isText$a(node) && node.data.length > 0;
  7909. const restoreEndPoint = (dom, suffix, bookmark) => {
  7910. const marker = dom.get(bookmark.id + '_' + suffix);
  7911. const markerParent = marker === null || marker === void 0 ? void 0 : marker.parentNode;
  7912. const keep = bookmark.keep;
  7913. if (marker && markerParent) {
  7914. let container;
  7915. let offset;
  7916. if (suffix === 'start') {
  7917. if (!keep) {
  7918. container = markerParent;
  7919. offset = dom.nodeIndex(marker);
  7920. } else {
  7921. if (marker.hasChildNodes()) {
  7922. container = marker.firstChild;
  7923. offset = 1;
  7924. } else if (isValidTextNode(marker.nextSibling)) {
  7925. container = marker.nextSibling;
  7926. offset = 0;
  7927. } else if (isValidTextNode(marker.previousSibling)) {
  7928. container = marker.previousSibling;
  7929. offset = marker.previousSibling.data.length;
  7930. } else {
  7931. container = markerParent;
  7932. offset = dom.nodeIndex(marker) + 1;
  7933. }
  7934. }
  7935. } else {
  7936. if (!keep) {
  7937. container = markerParent;
  7938. offset = dom.nodeIndex(marker);
  7939. } else {
  7940. if (marker.hasChildNodes()) {
  7941. container = marker.firstChild;
  7942. offset = 1;
  7943. } else if (isValidTextNode(marker.previousSibling)) {
  7944. container = marker.previousSibling;
  7945. offset = marker.previousSibling.data.length;
  7946. } else {
  7947. container = markerParent;
  7948. offset = dom.nodeIndex(marker);
  7949. }
  7950. }
  7951. }
  7952. if (!keep) {
  7953. const prev = marker.previousSibling;
  7954. const next = marker.nextSibling;
  7955. Tools.each(Tools.grep(marker.childNodes), node => {
  7956. if (isText$a(node)) {
  7957. node.data = node.data.replace(/\uFEFF/g, '');
  7958. }
  7959. });
  7960. let otherMarker;
  7961. while (otherMarker = dom.get(bookmark.id + '_' + suffix)) {
  7962. dom.remove(otherMarker, true);
  7963. }
  7964. if (isText$a(next) && isText$a(prev) && !Env.browser.isOpera()) {
  7965. const idx = prev.data.length;
  7966. prev.appendData(next.data);
  7967. dom.remove(next);
  7968. container = prev;
  7969. offset = idx;
  7970. }
  7971. }
  7972. return Optional.some(CaretPosition(container, offset));
  7973. } else {
  7974. return Optional.none();
  7975. }
  7976. };
  7977. const resolvePaths = (dom, bookmark) => {
  7978. const range = dom.createRng();
  7979. if (setEndPoint(dom, true, bookmark, range) && setEndPoint(dom, false, bookmark, range)) {
  7980. return Optional.some({
  7981. range,
  7982. forward: isForwardBookmark(bookmark)
  7983. });
  7984. } else {
  7985. return Optional.none();
  7986. }
  7987. };
  7988. const resolveId = (dom, bookmark) => {
  7989. const startPos = restoreEndPoint(dom, 'start', bookmark);
  7990. const endPos = restoreEndPoint(dom, 'end', bookmark);
  7991. return lift2(startPos, endPos.or(startPos), (spos, epos) => {
  7992. const range = dom.createRng();
  7993. range.setStart(addBogus(dom, spos.container()), spos.offset());
  7994. range.setEnd(addBogus(dom, epos.container()), epos.offset());
  7995. return {
  7996. range,
  7997. forward: isForwardBookmark(bookmark)
  7998. };
  7999. });
  8000. };
  8001. const resolveIndex = (dom, bookmark) => Optional.from(dom.select(bookmark.name)[bookmark.index]).map(elm => {
  8002. const range = dom.createRng();
  8003. range.selectNode(elm);
  8004. return {
  8005. range,
  8006. forward: true
  8007. };
  8008. });
  8009. const resolve = (selection, bookmark) => {
  8010. const dom = selection.dom;
  8011. if (bookmark) {
  8012. if (isPathBookmark(bookmark)) {
  8013. return resolvePaths(dom, bookmark);
  8014. } else if (isStringPathBookmark(bookmark)) {
  8015. return resolveCaretPositionBookmark(dom, bookmark);
  8016. } else if (isIdBookmark(bookmark)) {
  8017. return resolveId(dom, bookmark);
  8018. } else if (isIndexBookmark(bookmark)) {
  8019. return resolveIndex(dom, bookmark);
  8020. } else if (isRangeBookmark(bookmark)) {
  8021. return Optional.some({
  8022. range: bookmark.rng,
  8023. forward: isForwardBookmark(bookmark)
  8024. });
  8025. }
  8026. }
  8027. return Optional.none();
  8028. };
  8029. const getBookmark$1 = (selection, type, normalized) => {
  8030. return getBookmark$2(selection, type, normalized);
  8031. };
  8032. const moveToBookmark = (selection, bookmark) => {
  8033. resolve(selection, bookmark).each(({range, forward}) => {
  8034. selection.setRng(range, forward);
  8035. });
  8036. };
  8037. const isBookmarkNode$1 = node => {
  8038. return isElement$6(node) && node.tagName === 'SPAN' && node.getAttribute('data-mce-type') === 'bookmark';
  8039. };
  8040. const is = expected => actual => expected === actual;
  8041. const isNbsp = is(nbsp);
  8042. const isWhiteSpace = chr => chr !== '' && ' \f\n\r\t\x0B'.indexOf(chr) !== -1;
  8043. const isContent = chr => !isWhiteSpace(chr) && !isNbsp(chr) && !isZwsp$1(chr);
  8044. const hexColour = value => ({ value });
  8045. const toHex = component => {
  8046. const hex = component.toString(16);
  8047. return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
  8048. };
  8049. const fromRgba = rgbaColour => {
  8050. const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
  8051. return hexColour(value);
  8052. };
  8053. const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  8054. const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  8055. const rgbaColour = (red, green, blue, alpha) => ({
  8056. red,
  8057. green,
  8058. blue,
  8059. alpha
  8060. });
  8061. const fromStringValues = (red, green, blue, alpha) => {
  8062. const r = parseInt(red, 10);
  8063. const g = parseInt(green, 10);
  8064. const b = parseInt(blue, 10);
  8065. const a = parseFloat(alpha);
  8066. return rgbaColour(r, g, b, a);
  8067. };
  8068. const fromString = rgbaString => {
  8069. if (rgbaString === 'transparent') {
  8070. return Optional.some(rgbaColour(0, 0, 0, 0));
  8071. }
  8072. const rgbMatch = rgbRegex.exec(rgbaString);
  8073. if (rgbMatch !== null) {
  8074. return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
  8075. }
  8076. const rgbaMatch = rgbaRegex.exec(rgbaString);
  8077. if (rgbaMatch !== null) {
  8078. return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
  8079. }
  8080. return Optional.none();
  8081. };
  8082. const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
  8083. const getRanges$1 = selection => {
  8084. const ranges = [];
  8085. if (selection) {
  8086. for (let i = 0; i < selection.rangeCount; i++) {
  8087. ranges.push(selection.getRangeAt(i));
  8088. }
  8089. }
  8090. return ranges;
  8091. };
  8092. const getSelectedNodes = ranges => {
  8093. return bind$3(ranges, range => {
  8094. const node = getSelectedNode(range);
  8095. return node ? [SugarElement.fromDom(node)] : [];
  8096. });
  8097. };
  8098. const hasMultipleRanges = selection => {
  8099. return getRanges$1(selection).length > 1;
  8100. };
  8101. const getCellsFromRanges = ranges => filter$5(getSelectedNodes(ranges), isTableCell$2);
  8102. const getCellsFromElement = elm => descendants(elm, 'td[data-mce-selected],th[data-mce-selected]');
  8103. const getCellsFromElementOrRanges = (ranges, element) => {
  8104. const selectedCells = getCellsFromElement(element);
  8105. return selectedCells.length > 0 ? selectedCells : getCellsFromRanges(ranges);
  8106. };
  8107. const getCellsFromEditor = editor => getCellsFromElementOrRanges(getRanges$1(editor.selection.getSel()), SugarElement.fromDom(editor.getBody()));
  8108. const getClosestTable = (cell, isRoot) => ancestor$2(cell, 'table', isRoot);
  8109. const getStartNode = rng => {
  8110. const sc = rng.startContainer, so = rng.startOffset;
  8111. if (isText$a(sc)) {
  8112. return so === 0 ? Optional.some(SugarElement.fromDom(sc)) : Optional.none();
  8113. } else {
  8114. return Optional.from(sc.childNodes[so]).map(SugarElement.fromDom);
  8115. }
  8116. };
  8117. const getEndNode = rng => {
  8118. const ec = rng.endContainer, eo = rng.endOffset;
  8119. if (isText$a(ec)) {
  8120. return eo === ec.data.length ? Optional.some(SugarElement.fromDom(ec)) : Optional.none();
  8121. } else {
  8122. return Optional.from(ec.childNodes[eo - 1]).map(SugarElement.fromDom);
  8123. }
  8124. };
  8125. const getFirstChildren = node => {
  8126. return firstChild(node).fold(constant([node]), child => {
  8127. return [node].concat(getFirstChildren(child));
  8128. });
  8129. };
  8130. const getLastChildren = node => {
  8131. return lastChild(node).fold(constant([node]), child => {
  8132. if (name(child) === 'br') {
  8133. return prevSibling(child).map(sibling => {
  8134. return [node].concat(getLastChildren(sibling));
  8135. }).getOr([]);
  8136. } else {
  8137. return [node].concat(getLastChildren(child));
  8138. }
  8139. });
  8140. };
  8141. const hasAllContentsSelected = (elm, rng) => {
  8142. return lift2(getStartNode(rng), getEndNode(rng), (startNode, endNode) => {
  8143. const start = find$2(getFirstChildren(elm), curry(eq, startNode));
  8144. const end = find$2(getLastChildren(elm), curry(eq, endNode));
  8145. return start.isSome() && end.isSome();
  8146. }).getOr(false);
  8147. };
  8148. const moveEndPoint = (dom, rng, node, start) => {
  8149. const root = node;
  8150. const walker = new DomTreeWalker(node, root);
  8151. const moveCaretBeforeOnEnterElementsMap = filter$4(dom.schema.getMoveCaretBeforeOnEnterElements(), (_, name) => !contains$2([
  8152. 'td',
  8153. 'th',
  8154. 'table'
  8155. ], name.toLowerCase()));
  8156. let currentNode = node;
  8157. do {
  8158. if (isText$a(currentNode) && Tools.trim(currentNode.data).length !== 0) {
  8159. if (start) {
  8160. rng.setStart(currentNode, 0);
  8161. } else {
  8162. rng.setEnd(currentNode, currentNode.data.length);
  8163. }
  8164. return;
  8165. }
  8166. if (moveCaretBeforeOnEnterElementsMap[currentNode.nodeName]) {
  8167. if (start) {
  8168. rng.setStartBefore(currentNode);
  8169. } else {
  8170. if (currentNode.nodeName === 'BR') {
  8171. rng.setEndBefore(currentNode);
  8172. } else {
  8173. rng.setEndAfter(currentNode);
  8174. }
  8175. }
  8176. return;
  8177. }
  8178. } while (currentNode = start ? walker.next() : walker.prev());
  8179. if (root.nodeName === 'BODY') {
  8180. if (start) {
  8181. rng.setStart(root, 0);
  8182. } else {
  8183. rng.setEnd(root, root.childNodes.length);
  8184. }
  8185. }
  8186. };
  8187. const hasAnyRanges = editor => {
  8188. const sel = editor.selection.getSel();
  8189. return isNonNullable(sel) && sel.rangeCount > 0;
  8190. };
  8191. const runOnRanges = (editor, executor) => {
  8192. const fakeSelectionNodes = getCellsFromEditor(editor);
  8193. if (fakeSelectionNodes.length > 0) {
  8194. each$e(fakeSelectionNodes, elem => {
  8195. const node = elem.dom;
  8196. const fakeNodeRng = editor.dom.createRng();
  8197. fakeNodeRng.setStartBefore(node);
  8198. fakeNodeRng.setEndAfter(node);
  8199. executor(fakeNodeRng, true);
  8200. });
  8201. } else {
  8202. executor(editor.selection.getRng(), false);
  8203. }
  8204. };
  8205. const preserve = (selection, fillBookmark, executor) => {
  8206. const bookmark = getPersistentBookmark(selection, fillBookmark);
  8207. executor(bookmark);
  8208. selection.moveToBookmark(bookmark);
  8209. };
  8210. const isNode = node => isNumber(node === null || node === void 0 ? void 0 : node.nodeType);
  8211. const isElementNode$1 = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
  8212. const isElementDirectlySelected = (dom, node) => {
  8213. if (isElementNode$1(node) && !/^(TD|TH)$/.test(node.nodeName)) {
  8214. const selectedAttr = dom.getAttrib(node, 'data-mce-selected');
  8215. const value = parseInt(selectedAttr, 10);
  8216. return !isNaN(value) && value > 0;
  8217. } else {
  8218. return false;
  8219. }
  8220. };
  8221. const isEditable$3 = elm => elm.isContentEditable === true;
  8222. const preserveSelection = (editor, action, shouldMoveStart) => {
  8223. const {selection, dom} = editor;
  8224. const selectedNodeBeforeAction = selection.getNode();
  8225. const isSelectedBeforeNodeNoneditable = isContentEditableFalse$a(selectedNodeBeforeAction);
  8226. preserve(selection, true, () => {
  8227. action();
  8228. });
  8229. const isBeforeNodeStillNoneditable = isSelectedBeforeNodeNoneditable && isContentEditableFalse$a(selectedNodeBeforeAction);
  8230. if (isBeforeNodeStillNoneditable && dom.isChildOf(selectedNodeBeforeAction, editor.getBody())) {
  8231. editor.selection.select(selectedNodeBeforeAction);
  8232. } else if (shouldMoveStart(selection.getStart())) {
  8233. moveStartToNearestText(dom, selection);
  8234. }
  8235. };
  8236. const moveStartToNearestText = (dom, selection) => {
  8237. var _a, _b;
  8238. const rng = selection.getRng();
  8239. const {startContainer, startOffset} = rng;
  8240. const selectedNode = selection.getNode();
  8241. if (isElementDirectlySelected(dom, selectedNode)) {
  8242. return;
  8243. }
  8244. if (isElement$6(startContainer)) {
  8245. const nodes = startContainer.childNodes;
  8246. const root = dom.getRoot();
  8247. let walker;
  8248. if (startOffset < nodes.length) {
  8249. const startNode = nodes[startOffset];
  8250. walker = new DomTreeWalker(startNode, (_a = dom.getParent(startNode, dom.isBlock)) !== null && _a !== void 0 ? _a : root);
  8251. } else {
  8252. const startNode = nodes[nodes.length - 1];
  8253. walker = new DomTreeWalker(startNode, (_b = dom.getParent(startNode, dom.isBlock)) !== null && _b !== void 0 ? _b : root);
  8254. walker.next(true);
  8255. }
  8256. for (let node = walker.current(); node; node = walker.next()) {
  8257. if (dom.getContentEditable(node) === 'false') {
  8258. return;
  8259. } else if (isText$a(node) && !isWhiteSpaceNode$1(node)) {
  8260. rng.setStart(node, 0);
  8261. selection.setRng(rng);
  8262. return;
  8263. }
  8264. }
  8265. }
  8266. };
  8267. const getNonWhiteSpaceSibling = (node, next, inc) => {
  8268. if (node) {
  8269. const nextName = next ? 'nextSibling' : 'previousSibling';
  8270. for (node = inc ? node : node[nextName]; node; node = node[nextName]) {
  8271. if (isElement$6(node) || !isWhiteSpaceNode$1(node)) {
  8272. return node;
  8273. }
  8274. }
  8275. }
  8276. return undefined;
  8277. };
  8278. const isTextBlock$1 = (schema, node) => !!schema.getTextBlockElements()[node.nodeName.toLowerCase()] || isTransparentBlock(schema, node);
  8279. const isValid = (ed, parent, child) => {
  8280. return ed.schema.isValidChild(parent, child);
  8281. };
  8282. const isWhiteSpaceNode$1 = (node, allowSpaces = false) => {
  8283. if (isNonNullable(node) && isText$a(node)) {
  8284. const data = allowSpaces ? node.data.replace(/ /g, '\xA0') : node.data;
  8285. return isWhitespaceText(data);
  8286. } else {
  8287. return false;
  8288. }
  8289. };
  8290. const isEmptyTextNode$1 = node => {
  8291. return isNonNullable(node) && isText$a(node) && node.length === 0;
  8292. };
  8293. const isWrapNoneditableTarget = (editor, node) => {
  8294. const baseDataSelector = '[data-mce-cef-wrappable]';
  8295. const formatNoneditableSelector = getFormatNoneditableSelector(editor);
  8296. const selector = isEmpty$3(formatNoneditableSelector) ? baseDataSelector : `${ baseDataSelector },${ formatNoneditableSelector }`;
  8297. return is$1(SugarElement.fromDom(node), selector);
  8298. };
  8299. const isWrappableNoneditable = (editor, node) => {
  8300. const dom = editor.dom;
  8301. return isElementNode$1(node) && dom.getContentEditable(node) === 'false' && isWrapNoneditableTarget(editor, node) && dom.select('[contenteditable="true"]', node).length === 0;
  8302. };
  8303. const replaceVars = (value, vars) => {
  8304. if (isFunction(value)) {
  8305. return value(vars);
  8306. } else if (isNonNullable(vars)) {
  8307. value = value.replace(/%(\w+)/g, (str, name) => {
  8308. return vars[name] || str;
  8309. });
  8310. }
  8311. return value;
  8312. };
  8313. const isEq$5 = (str1, str2) => {
  8314. str1 = str1 || '';
  8315. str2 = str2 || '';
  8316. str1 = '' + (str1.nodeName || str1);
  8317. str2 = '' + (str2.nodeName || str2);
  8318. return str1.toLowerCase() === str2.toLowerCase();
  8319. };
  8320. const normalizeStyleValue = (value, name) => {
  8321. if (isNullable(value)) {
  8322. return null;
  8323. } else {
  8324. let strValue = String(value);
  8325. if (name === 'color' || name === 'backgroundColor') {
  8326. strValue = rgbaToHexString(strValue);
  8327. }
  8328. if (name === 'fontWeight' && value === 700) {
  8329. strValue = 'bold';
  8330. }
  8331. if (name === 'fontFamily') {
  8332. strValue = strValue.replace(/[\'\"]/g, '').replace(/,\s+/g, ',');
  8333. }
  8334. return strValue;
  8335. }
  8336. };
  8337. const getStyle = (dom, node, name) => {
  8338. const style = dom.getStyle(node, name);
  8339. return normalizeStyleValue(style, name);
  8340. };
  8341. const getTextDecoration = (dom, node) => {
  8342. let decoration;
  8343. dom.getParent(node, n => {
  8344. if (isElement$6(n)) {
  8345. decoration = dom.getStyle(n, 'text-decoration');
  8346. return !!decoration && decoration !== 'none';
  8347. } else {
  8348. return false;
  8349. }
  8350. });
  8351. return decoration;
  8352. };
  8353. const getParents$2 = (dom, node, selector) => {
  8354. return dom.getParents(node, selector, dom.getRoot());
  8355. };
  8356. const isFormatPredicate = (editor, formatName, predicate) => {
  8357. const formats = editor.formatter.get(formatName);
  8358. return isNonNullable(formats) && exists(formats, predicate);
  8359. };
  8360. const isVariableFormatName = (editor, formatName) => {
  8361. const hasVariableValues = format => {
  8362. const isVariableValue = val => isFunction(val) || val.length > 1 && val.charAt(0) === '%';
  8363. return exists([
  8364. 'styles',
  8365. 'attributes'
  8366. ], key => get$a(format, key).exists(field => {
  8367. const fieldValues = isArray$1(field) ? field : values(field);
  8368. return exists(fieldValues, isVariableValue);
  8369. }));
  8370. };
  8371. return isFormatPredicate(editor, formatName, hasVariableValues);
  8372. };
  8373. const areSimilarFormats = (editor, formatName, otherFormatName) => {
  8374. const validKeys = [
  8375. 'inline',
  8376. 'block',
  8377. 'selector',
  8378. 'attributes',
  8379. 'styles',
  8380. 'classes'
  8381. ];
  8382. const filterObj = format => filter$4(format, (_, key) => exists(validKeys, validKey => validKey === key));
  8383. return isFormatPredicate(editor, formatName, fmt1 => {
  8384. const filteredFmt1 = filterObj(fmt1);
  8385. return isFormatPredicate(editor, otherFormatName, fmt2 => {
  8386. const filteredFmt2 = filterObj(fmt2);
  8387. return equal$1(filteredFmt1, filteredFmt2);
  8388. });
  8389. });
  8390. };
  8391. const isBlockFormat = format => hasNonNullableKey(format, 'block');
  8392. const isWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper === true;
  8393. const isNonWrappingBlockFormat = format => isBlockFormat(format) && format.wrapper !== true;
  8394. const isSelectorFormat = format => hasNonNullableKey(format, 'selector');
  8395. const isInlineFormat = format => hasNonNullableKey(format, 'inline');
  8396. const isMixedFormat = format => isSelectorFormat(format) && isInlineFormat(format) && is$2(get$a(format, 'mixed'), true);
  8397. const shouldExpandToSelector = format => isSelectorFormat(format) && format.expand !== false && !isInlineFormat(format);
  8398. const isBookmarkNode = isBookmarkNode$1;
  8399. const getParents$1 = getParents$2;
  8400. const isWhiteSpaceNode = isWhiteSpaceNode$1;
  8401. const isTextBlock = isTextBlock$1;
  8402. const isBogusBr = node => {
  8403. return isBr$6(node) && node.getAttribute('data-mce-bogus') && !node.nextSibling;
  8404. };
  8405. const findParentContentEditable = (dom, node) => {
  8406. let parent = node;
  8407. while (parent) {
  8408. if (isElement$6(parent) && dom.getContentEditable(parent)) {
  8409. return dom.getContentEditable(parent) === 'false' ? parent : node;
  8410. }
  8411. parent = parent.parentNode;
  8412. }
  8413. return node;
  8414. };
  8415. const walkText = (start, node, offset, predicate) => {
  8416. const str = node.data;
  8417. if (start) {
  8418. for (let i = offset; i > 0; i--) {
  8419. if (predicate(str.charAt(i - 1))) {
  8420. return i;
  8421. }
  8422. }
  8423. } else {
  8424. for (let i = offset; i < str.length; i++) {
  8425. if (predicate(str.charAt(i))) {
  8426. return i;
  8427. }
  8428. }
  8429. }
  8430. return -1;
  8431. };
  8432. const findSpace = (start, node, offset) => walkText(start, node, offset, c => isNbsp(c) || isWhiteSpace(c));
  8433. const findContent = (start, node, offset) => walkText(start, node, offset, isContent);
  8434. const findWordEndPoint = (dom, body, container, offset, start, includeTrailingSpaces) => {
  8435. let lastTextNode;
  8436. const rootNode = dom.getParent(container, dom.isBlock) || body;
  8437. const walk = (container, offset, pred) => {
  8438. const textSeeker = TextSeeker(dom);
  8439. const walker = start ? textSeeker.backwards : textSeeker.forwards;
  8440. return Optional.from(walker(container, offset, (text, textOffset) => {
  8441. if (isBookmarkNode(text.parentNode)) {
  8442. return -1;
  8443. } else {
  8444. lastTextNode = text;
  8445. return pred(start, text, textOffset);
  8446. }
  8447. }, rootNode));
  8448. };
  8449. const spaceResult = walk(container, offset, findSpace);
  8450. return spaceResult.bind(result => includeTrailingSpaces ? walk(result.container, result.offset + (start ? -1 : 0), findContent) : Optional.some(result)).orThunk(() => lastTextNode ? Optional.some({
  8451. container: lastTextNode,
  8452. offset: start ? 0 : lastTextNode.length
  8453. }) : Optional.none());
  8454. };
  8455. const findSelectorEndPoint = (dom, formatList, rng, container, siblingName) => {
  8456. const sibling = container[siblingName];
  8457. if (isText$a(container) && isEmpty$3(container.data) && sibling) {
  8458. container = sibling;
  8459. }
  8460. const parents = getParents$1(dom, container);
  8461. for (let i = 0; i < parents.length; i++) {
  8462. for (let y = 0; y < formatList.length; y++) {
  8463. const curFormat = formatList[y];
  8464. if (isNonNullable(curFormat.collapsed) && curFormat.collapsed !== rng.collapsed) {
  8465. continue;
  8466. }
  8467. if (isSelectorFormat(curFormat) && dom.is(parents[i], curFormat.selector)) {
  8468. return parents[i];
  8469. }
  8470. }
  8471. }
  8472. return container;
  8473. };
  8474. const findBlockEndPoint = (dom, formatList, container, siblingName) => {
  8475. var _a;
  8476. let node = container;
  8477. const root = dom.getRoot();
  8478. const format = formatList[0];
  8479. if (isBlockFormat(format)) {
  8480. node = format.wrapper ? null : dom.getParent(container, format.block, root);
  8481. }
  8482. if (!node) {
  8483. const scopeRoot = (_a = dom.getParent(container, 'LI,TD,TH')) !== null && _a !== void 0 ? _a : root;
  8484. node = dom.getParent(isText$a(container) ? container.parentNode : container, node => node !== root && isTextBlock(dom.schema, node), scopeRoot);
  8485. }
  8486. if (node && isBlockFormat(format) && format.wrapper) {
  8487. node = getParents$1(dom, node, 'ul,ol').reverse()[0] || node;
  8488. }
  8489. if (!node) {
  8490. node = container;
  8491. while (node && node[siblingName] && !dom.isBlock(node[siblingName])) {
  8492. node = node[siblingName];
  8493. if (isEq$5(node, 'br')) {
  8494. break;
  8495. }
  8496. }
  8497. }
  8498. return node || container;
  8499. };
  8500. const isAtBlockBoundary$1 = (dom, root, container, siblingName) => {
  8501. const parent = container.parentNode;
  8502. if (isNonNullable(container[siblingName])) {
  8503. return false;
  8504. } else if (parent === root || isNullable(parent) || dom.isBlock(parent)) {
  8505. return true;
  8506. } else {
  8507. return isAtBlockBoundary$1(dom, root, parent, siblingName);
  8508. }
  8509. };
  8510. const findParentContainer = (dom, formatList, container, offset, start) => {
  8511. let parent = container;
  8512. const siblingName = start ? 'previousSibling' : 'nextSibling';
  8513. const root = dom.getRoot();
  8514. if (isText$a(container) && !isWhiteSpaceNode(container)) {
  8515. if (start ? offset > 0 : offset < container.data.length) {
  8516. return container;
  8517. }
  8518. }
  8519. while (parent) {
  8520. if (!formatList[0].block_expand && dom.isBlock(parent)) {
  8521. return parent;
  8522. }
  8523. for (let sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
  8524. const allowSpaces = isText$a(sibling) && !isAtBlockBoundary$1(dom, root, sibling, siblingName);
  8525. if (!isBookmarkNode(sibling) && !isBogusBr(sibling) && !isWhiteSpaceNode(sibling, allowSpaces)) {
  8526. return parent;
  8527. }
  8528. }
  8529. if (parent === root || parent.parentNode === root) {
  8530. container = parent;
  8531. break;
  8532. }
  8533. parent = parent.parentNode;
  8534. }
  8535. return container;
  8536. };
  8537. const isSelfOrParentBookmark = container => isBookmarkNode(container.parentNode) || isBookmarkNode(container);
  8538. const expandRng = (dom, rng, formatList, includeTrailingSpace = false) => {
  8539. let {startContainer, startOffset, endContainer, endOffset} = rng;
  8540. const format = formatList[0];
  8541. if (isElement$6(startContainer) && startContainer.hasChildNodes()) {
  8542. startContainer = getNode$1(startContainer, startOffset);
  8543. if (isText$a(startContainer)) {
  8544. startOffset = 0;
  8545. }
  8546. }
  8547. if (isElement$6(endContainer) && endContainer.hasChildNodes()) {
  8548. endContainer = getNode$1(endContainer, rng.collapsed ? endOffset : endOffset - 1);
  8549. if (isText$a(endContainer)) {
  8550. endOffset = endContainer.data.length;
  8551. }
  8552. }
  8553. startContainer = findParentContentEditable(dom, startContainer);
  8554. endContainer = findParentContentEditable(dom, endContainer);
  8555. if (isSelfOrParentBookmark(startContainer)) {
  8556. startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
  8557. if (rng.collapsed) {
  8558. startContainer = startContainer.previousSibling || startContainer;
  8559. } else {
  8560. startContainer = startContainer.nextSibling || startContainer;
  8561. }
  8562. if (isText$a(startContainer)) {
  8563. startOffset = rng.collapsed ? startContainer.length : 0;
  8564. }
  8565. }
  8566. if (isSelfOrParentBookmark(endContainer)) {
  8567. endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
  8568. if (rng.collapsed) {
  8569. endContainer = endContainer.nextSibling || endContainer;
  8570. } else {
  8571. endContainer = endContainer.previousSibling || endContainer;
  8572. }
  8573. if (isText$a(endContainer)) {
  8574. endOffset = rng.collapsed ? 0 : endContainer.length;
  8575. }
  8576. }
  8577. if (rng.collapsed) {
  8578. const startPoint = findWordEndPoint(dom, dom.getRoot(), startContainer, startOffset, true, includeTrailingSpace);
  8579. startPoint.each(({container, offset}) => {
  8580. startContainer = container;
  8581. startOffset = offset;
  8582. });
  8583. const endPoint = findWordEndPoint(dom, dom.getRoot(), endContainer, endOffset, false, includeTrailingSpace);
  8584. endPoint.each(({container, offset}) => {
  8585. endContainer = container;
  8586. endOffset = offset;
  8587. });
  8588. }
  8589. if (isInlineFormat(format) || format.block_expand) {
  8590. if (!isInlineFormat(format) || (!isText$a(startContainer) || startOffset === 0)) {
  8591. startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
  8592. }
  8593. if (!isInlineFormat(format) || (!isText$a(endContainer) || endOffset === endContainer.data.length)) {
  8594. endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
  8595. }
  8596. }
  8597. if (shouldExpandToSelector(format)) {
  8598. startContainer = findSelectorEndPoint(dom, formatList, rng, startContainer, 'previousSibling');
  8599. endContainer = findSelectorEndPoint(dom, formatList, rng, endContainer, 'nextSibling');
  8600. }
  8601. if (isBlockFormat(format) || isSelectorFormat(format)) {
  8602. startContainer = findBlockEndPoint(dom, formatList, startContainer, 'previousSibling');
  8603. endContainer = findBlockEndPoint(dom, formatList, endContainer, 'nextSibling');
  8604. if (isBlockFormat(format)) {
  8605. if (!dom.isBlock(startContainer)) {
  8606. startContainer = findParentContainer(dom, formatList, startContainer, startOffset, true);
  8607. }
  8608. if (!dom.isBlock(endContainer)) {
  8609. endContainer = findParentContainer(dom, formatList, endContainer, endOffset, false);
  8610. }
  8611. }
  8612. }
  8613. if (isElement$6(startContainer) && startContainer.parentNode) {
  8614. startOffset = dom.nodeIndex(startContainer);
  8615. startContainer = startContainer.parentNode;
  8616. }
  8617. if (isElement$6(endContainer) && endContainer.parentNode) {
  8618. endOffset = dom.nodeIndex(endContainer) + 1;
  8619. endContainer = endContainer.parentNode;
  8620. }
  8621. return {
  8622. startContainer,
  8623. startOffset,
  8624. endContainer,
  8625. endOffset
  8626. };
  8627. };
  8628. const walk$3 = (dom, rng, callback) => {
  8629. var _a;
  8630. const startOffset = rng.startOffset;
  8631. const startContainer = getNode$1(rng.startContainer, startOffset);
  8632. const endOffset = rng.endOffset;
  8633. const endContainer = getNode$1(rng.endContainer, endOffset - 1);
  8634. const exclude = nodes => {
  8635. const firstNode = nodes[0];
  8636. if (isText$a(firstNode) && firstNode === startContainer && startOffset >= firstNode.data.length) {
  8637. nodes.splice(0, 1);
  8638. }
  8639. const lastNode = nodes[nodes.length - 1];
  8640. if (endOffset === 0 && nodes.length > 0 && lastNode === endContainer && isText$a(lastNode)) {
  8641. nodes.splice(nodes.length - 1, 1);
  8642. }
  8643. return nodes;
  8644. };
  8645. const collectSiblings = (node, name, endNode) => {
  8646. const siblings = [];
  8647. for (; node && node !== endNode; node = node[name]) {
  8648. siblings.push(node);
  8649. }
  8650. return siblings;
  8651. };
  8652. const findEndPoint = (node, root) => dom.getParent(node, node => node.parentNode === root, root);
  8653. const walkBoundary = (startNode, endNode, next) => {
  8654. const siblingName = next ? 'nextSibling' : 'previousSibling';
  8655. for (let node = startNode, parent = node.parentNode; node && node !== endNode; node = parent) {
  8656. parent = node.parentNode;
  8657. const siblings = collectSiblings(node === startNode ? node : node[siblingName], siblingName);
  8658. if (siblings.length) {
  8659. if (!next) {
  8660. siblings.reverse();
  8661. }
  8662. callback(exclude(siblings));
  8663. }
  8664. }
  8665. };
  8666. if (startContainer === endContainer) {
  8667. return callback(exclude([startContainer]));
  8668. }
  8669. const ancestor = (_a = dom.findCommonAncestor(startContainer, endContainer)) !== null && _a !== void 0 ? _a : dom.getRoot();
  8670. if (dom.isChildOf(startContainer, endContainer)) {
  8671. return walkBoundary(startContainer, ancestor, true);
  8672. }
  8673. if (dom.isChildOf(endContainer, startContainer)) {
  8674. return walkBoundary(endContainer, ancestor);
  8675. }
  8676. const startPoint = findEndPoint(startContainer, ancestor) || startContainer;
  8677. const endPoint = findEndPoint(endContainer, ancestor) || endContainer;
  8678. walkBoundary(startContainer, startPoint, true);
  8679. const siblings = collectSiblings(startPoint === startContainer ? startPoint : startPoint.nextSibling, 'nextSibling', endPoint === endContainer ? endPoint.nextSibling : endPoint);
  8680. if (siblings.length) {
  8681. callback(exclude(siblings));
  8682. }
  8683. walkBoundary(endContainer, endPoint);
  8684. };
  8685. const validBlocks = [
  8686. 'pre[class*=language-][contenteditable="false"]',
  8687. 'figure.image',
  8688. 'div[data-ephox-embed-iri]',
  8689. 'div.tiny-pageembed',
  8690. 'div.mce-toc',
  8691. 'div[data-mce-toc]'
  8692. ];
  8693. const isZeroWidth = elem => isText$b(elem) && get$3(elem) === ZWSP$1;
  8694. const context = (editor, elem, wrapName, nodeName) => parent(elem).fold(() => 'skipping', parent => {
  8695. if (nodeName === 'br' || isZeroWidth(elem)) {
  8696. return 'valid';
  8697. } else if (isAnnotation(elem)) {
  8698. return 'existing';
  8699. } else if (isCaretNode(elem.dom)) {
  8700. return 'caret';
  8701. } else if (exists(validBlocks, selector => is$1(elem, selector))) {
  8702. return 'valid-block';
  8703. } else if (!isValid(editor, wrapName, nodeName) || !isValid(editor, name(parent), wrapName)) {
  8704. return 'invalid-child';
  8705. } else {
  8706. return 'valid';
  8707. }
  8708. });
  8709. const applyWordGrab = (editor, rng) => {
  8710. const r = expandRng(editor.dom, rng, [{ inline: 'span' }]);
  8711. rng.setStart(r.startContainer, r.startOffset);
  8712. rng.setEnd(r.endContainer, r.endOffset);
  8713. editor.selection.setRng(rng);
  8714. };
  8715. const applyAnnotation = (elem, masterUId, data, annotationName, decorate, directAnnotation) => {
  8716. const {uid = masterUId, ...otherData} = data;
  8717. add$2(elem, annotation());
  8718. set$2(elem, `${ dataAnnotationId() }`, uid);
  8719. set$2(elem, `${ dataAnnotation() }`, annotationName);
  8720. const {attributes = {}, classes = []} = decorate(uid, otherData);
  8721. setAll$1(elem, attributes);
  8722. add(elem, classes);
  8723. if (directAnnotation) {
  8724. if (classes.length > 0) {
  8725. set$2(elem, `${ dataAnnotationClasses() }`, classes.join(','));
  8726. }
  8727. const attributeNames = keys(attributes);
  8728. if (attributeNames.length > 0) {
  8729. set$2(elem, `${ dataAnnotationAttributes() }`, attributeNames.join(','));
  8730. }
  8731. }
  8732. };
  8733. const removeDirectAnnotation = elem => {
  8734. remove$8(elem, annotation());
  8735. remove$b(elem, `${ dataAnnotationId() }`);
  8736. remove$b(elem, `${ dataAnnotation() }`);
  8737. remove$b(elem, `${ dataAnnotationActive() }`);
  8738. const customAttrNames = getOpt(elem, `${ dataAnnotationAttributes() }`).map(names => names.split(',')).getOr([]);
  8739. const customClasses = getOpt(elem, `${ dataAnnotationClasses() }`).map(names => names.split(',')).getOr([]);
  8740. each$e(customAttrNames, name => remove$b(elem, name));
  8741. remove$5(elem, customClasses);
  8742. remove$b(elem, `${ dataAnnotationClasses() }`);
  8743. remove$b(elem, `${ dataAnnotationAttributes() }`);
  8744. };
  8745. const makeAnnotation = (eDoc, uid, data, annotationName, decorate) => {
  8746. const master = SugarElement.fromTag('span', eDoc);
  8747. applyAnnotation(master, uid, data, annotationName, decorate, false);
  8748. return master;
  8749. };
  8750. const annotate = (editor, rng, uid, annotationName, decorate, data) => {
  8751. const newWrappers = [];
  8752. const master = makeAnnotation(editor.getDoc(), uid, data, annotationName, decorate);
  8753. const wrapper = value$2();
  8754. const finishWrapper = () => {
  8755. wrapper.clear();
  8756. };
  8757. const getOrOpenWrapper = () => wrapper.get().getOrThunk(() => {
  8758. const nu = shallow$1(master);
  8759. newWrappers.push(nu);
  8760. wrapper.set(nu);
  8761. return nu;
  8762. });
  8763. const processElements = elems => {
  8764. each$e(elems, processElement);
  8765. };
  8766. const processElement = elem => {
  8767. const ctx = context(editor, elem, 'span', name(elem));
  8768. switch (ctx) {
  8769. case 'invalid-child': {
  8770. finishWrapper();
  8771. const children = children$1(elem);
  8772. processElements(children);
  8773. finishWrapper();
  8774. break;
  8775. }
  8776. case 'valid-block': {
  8777. finishWrapper();
  8778. applyAnnotation(elem, uid, data, annotationName, decorate, true);
  8779. break;
  8780. }
  8781. case 'valid': {
  8782. const w = getOrOpenWrapper();
  8783. wrap$2(elem, w);
  8784. break;
  8785. }
  8786. }
  8787. };
  8788. const processNodes = nodes => {
  8789. const elems = map$3(nodes, SugarElement.fromDom);
  8790. processElements(elems);
  8791. };
  8792. walk$3(editor.dom, rng, nodes => {
  8793. finishWrapper();
  8794. processNodes(nodes);
  8795. });
  8796. return newWrappers;
  8797. };
  8798. const annotateWithBookmark = (editor, name, settings, data) => {
  8799. editor.undoManager.transact(() => {
  8800. const selection = editor.selection;
  8801. const initialRng = selection.getRng();
  8802. const hasFakeSelection = getCellsFromEditor(editor).length > 0;
  8803. const masterUid = generate$1('mce-annotation');
  8804. if (initialRng.collapsed && !hasFakeSelection) {
  8805. applyWordGrab(editor, initialRng);
  8806. }
  8807. if (selection.getRng().collapsed && !hasFakeSelection) {
  8808. const wrapper = makeAnnotation(editor.getDoc(), masterUid, data, name, settings.decorate);
  8809. set(wrapper, nbsp);
  8810. selection.getRng().insertNode(wrapper.dom);
  8811. selection.select(wrapper.dom);
  8812. } else {
  8813. preserve(selection, false, () => {
  8814. runOnRanges(editor, selectionRng => {
  8815. annotate(editor, selectionRng, masterUid, name, settings.decorate, data);
  8816. });
  8817. });
  8818. }
  8819. });
  8820. };
  8821. const Annotator = editor => {
  8822. const registry = create$c();
  8823. setup$w(editor, registry);
  8824. const changes = setup$x(editor, registry);
  8825. const isSpan = isTag('span');
  8826. const removeAnnotations = elements => {
  8827. each$e(elements, element => {
  8828. if (isSpan(element)) {
  8829. unwrap(element);
  8830. } else {
  8831. removeDirectAnnotation(element);
  8832. }
  8833. });
  8834. };
  8835. return {
  8836. register: (name, settings) => {
  8837. registry.register(name, settings);
  8838. },
  8839. annotate: (name, data) => {
  8840. registry.lookup(name).each(settings => {
  8841. annotateWithBookmark(editor, name, settings, data);
  8842. });
  8843. },
  8844. annotationChanged: (name, callback) => {
  8845. changes.addListener(name, callback);
  8846. },
  8847. remove: name => {
  8848. const bookmark = editor.selection.getBookmark();
  8849. identify(editor, Optional.some(name)).each(({elements}) => {
  8850. removeAnnotations(elements);
  8851. });
  8852. editor.selection.moveToBookmark(bookmark);
  8853. },
  8854. removeAll: name => {
  8855. const bookmark = editor.selection.getBookmark();
  8856. each$d(findAll(editor, name), (elements, _) => {
  8857. removeAnnotations(elements);
  8858. });
  8859. editor.selection.moveToBookmark(bookmark);
  8860. },
  8861. getAll: name => {
  8862. const directory = findAll(editor, name);
  8863. return map$2(directory, elems => map$3(elems, elem => elem.dom));
  8864. }
  8865. };
  8866. };
  8867. const BookmarkManager = selection => {
  8868. return {
  8869. getBookmark: curry(getBookmark$1, selection),
  8870. moveToBookmark: curry(moveToBookmark, selection)
  8871. };
  8872. };
  8873. BookmarkManager.isBookmarkNode = isBookmarkNode$1;
  8874. const isXYWithinRange = (clientX, clientY, range) => {
  8875. if (range.collapsed) {
  8876. return false;
  8877. } else {
  8878. return exists(range.getClientRects(), rect => containsXY(rect, clientX, clientY));
  8879. }
  8880. };
  8881. const firePreProcess = (editor, args) => editor.dispatch('PreProcess', args);
  8882. const firePostProcess = (editor, args) => editor.dispatch('PostProcess', args);
  8883. const fireRemove = editor => {
  8884. editor.dispatch('remove');
  8885. };
  8886. const fireDetach = editor => {
  8887. editor.dispatch('detach');
  8888. };
  8889. const fireSwitchMode = (editor, mode) => {
  8890. editor.dispatch('SwitchMode', { mode });
  8891. };
  8892. const fireObjectResizeStart = (editor, target, width, height, origin) => {
  8893. editor.dispatch('ObjectResizeStart', {
  8894. target,
  8895. width,
  8896. height,
  8897. origin
  8898. });
  8899. };
  8900. const fireObjectResized = (editor, target, width, height, origin) => {
  8901. editor.dispatch('ObjectResized', {
  8902. target,
  8903. width,
  8904. height,
  8905. origin
  8906. });
  8907. };
  8908. const firePreInit = editor => {
  8909. editor.dispatch('PreInit');
  8910. };
  8911. const firePostRender = editor => {
  8912. editor.dispatch('PostRender');
  8913. };
  8914. const fireInit = editor => {
  8915. editor.dispatch('Init');
  8916. };
  8917. const firePlaceholderToggle = (editor, state) => {
  8918. editor.dispatch('PlaceholderToggle', { state });
  8919. };
  8920. const fireError = (editor, errorType, error) => {
  8921. editor.dispatch(errorType, error);
  8922. };
  8923. const fireFormatApply = (editor, format, node, vars) => {
  8924. editor.dispatch('FormatApply', {
  8925. format,
  8926. node,
  8927. vars
  8928. });
  8929. };
  8930. const fireFormatRemove = (editor, format, node, vars) => {
  8931. editor.dispatch('FormatRemove', {
  8932. format,
  8933. node,
  8934. vars
  8935. });
  8936. };
  8937. const fireBeforeSetContent = (editor, args) => editor.dispatch('BeforeSetContent', args);
  8938. const fireSetContent = (editor, args) => editor.dispatch('SetContent', args);
  8939. const fireBeforeGetContent = (editor, args) => editor.dispatch('BeforeGetContent', args);
  8940. const fireGetContent = (editor, args) => editor.dispatch('GetContent', args);
  8941. const fireAutocompleterStart = (editor, args) => {
  8942. editor.dispatch('AutocompleterStart', args);
  8943. };
  8944. const fireAutocompleterUpdate = (editor, args) => {
  8945. editor.dispatch('AutocompleterUpdate', args);
  8946. };
  8947. const fireAutocompleterEnd = editor => {
  8948. editor.dispatch('AutocompleterEnd');
  8949. };
  8950. const firePastePreProcess = (editor, html, internal) => editor.dispatch('PastePreProcess', {
  8951. content: html,
  8952. internal
  8953. });
  8954. const firePastePostProcess = (editor, node, internal) => editor.dispatch('PastePostProcess', {
  8955. node,
  8956. internal
  8957. });
  8958. const firePastePlainTextToggle = (editor, state) => editor.dispatch('PastePlainTextToggle', { state });
  8959. const VK = {
  8960. BACKSPACE: 8,
  8961. DELETE: 46,
  8962. DOWN: 40,
  8963. ENTER: 13,
  8964. ESC: 27,
  8965. LEFT: 37,
  8966. RIGHT: 39,
  8967. SPACEBAR: 32,
  8968. TAB: 9,
  8969. UP: 38,
  8970. PAGE_UP: 33,
  8971. PAGE_DOWN: 34,
  8972. END: 35,
  8973. HOME: 36,
  8974. modifierPressed: e => {
  8975. return e.shiftKey || e.ctrlKey || e.altKey || VK.metaKeyPressed(e);
  8976. },
  8977. metaKeyPressed: e => {
  8978. return Env.os.isMacOS() || Env.os.isiOS() ? e.metaKey : e.ctrlKey && !e.altKey;
  8979. }
  8980. };
  8981. const elementSelectionAttr = 'data-mce-selected';
  8982. const controlElmSelector = 'table,img,figure.image,hr,video,span.mce-preview-object';
  8983. const abs = Math.abs;
  8984. const round$1 = Math.round;
  8985. const resizeHandles = {
  8986. nw: [
  8987. 0,
  8988. 0,
  8989. -1,
  8990. -1
  8991. ],
  8992. ne: [
  8993. 1,
  8994. 0,
  8995. 1,
  8996. -1
  8997. ],
  8998. se: [
  8999. 1,
  9000. 1,
  9001. 1,
  9002. 1
  9003. ],
  9004. sw: [
  9005. 0,
  9006. 1,
  9007. -1,
  9008. 1
  9009. ]
  9010. };
  9011. const isTouchEvent = evt => evt.type === 'longpress' || evt.type.indexOf('touch') === 0;
  9012. const ControlSelection = (selection, editor) => {
  9013. const dom = editor.dom;
  9014. const editableDoc = editor.getDoc();
  9015. const rootDocument = document;
  9016. const rootElement = editor.getBody();
  9017. let selectedElm, selectedElmGhost, resizeHelper, selectedHandle, resizeBackdrop;
  9018. let startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted;
  9019. let width;
  9020. let height;
  9021. let startScrollWidth;
  9022. let startScrollHeight;
  9023. const isImage = elm => isNonNullable(elm) && (isImg(elm) || dom.is(elm, 'figure.image'));
  9024. const isMedia = elm => isMedia$2(elm) || dom.hasClass(elm, 'mce-preview-object');
  9025. const isEventOnImageOutsideRange = (evt, range) => {
  9026. if (isTouchEvent(evt)) {
  9027. const touch = evt.touches[0];
  9028. return isImage(evt.target) && !isXYWithinRange(touch.clientX, touch.clientY, range);
  9029. } else {
  9030. return isImage(evt.target) && !isXYWithinRange(evt.clientX, evt.clientY, range);
  9031. }
  9032. };
  9033. const contextMenuSelectImage = evt => {
  9034. const target = evt.target;
  9035. if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) {
  9036. editor.selection.select(target);
  9037. }
  9038. };
  9039. const getResizeTargets = elm => {
  9040. if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
  9041. return [
  9042. elm,
  9043. elm.firstElementChild
  9044. ];
  9045. } else if (dom.is(elm, 'figure.image')) {
  9046. return [elm.querySelector('img')];
  9047. } else {
  9048. return [elm];
  9049. }
  9050. };
  9051. const isResizable = elm => {
  9052. const selector = getObjectResizing(editor);
  9053. if (!selector) {
  9054. return false;
  9055. }
  9056. if (elm.getAttribute('data-mce-resize') === 'false') {
  9057. return false;
  9058. }
  9059. if (elm === editor.getBody()) {
  9060. return false;
  9061. }
  9062. if (dom.hasClass(elm, 'mce-preview-object') && isNonNullable(elm.firstElementChild)) {
  9063. return is$1(SugarElement.fromDom(elm.firstElementChild), selector);
  9064. } else {
  9065. return is$1(SugarElement.fromDom(elm), selector);
  9066. }
  9067. };
  9068. const createGhostElement = elm => {
  9069. if (isMedia(elm)) {
  9070. return dom.create('img', { src: Env.transparentSrc });
  9071. } else {
  9072. return elm.cloneNode(true);
  9073. }
  9074. };
  9075. const setSizeProp = (element, name, value) => {
  9076. if (isNonNullable(value)) {
  9077. const targets = getResizeTargets(element);
  9078. each$e(targets, target => {
  9079. if (target.style[name] || !editor.schema.isValid(target.nodeName.toLowerCase(), name)) {
  9080. dom.setStyle(target, name, value);
  9081. } else {
  9082. dom.setAttrib(target, name, '' + value);
  9083. }
  9084. });
  9085. }
  9086. };
  9087. const setGhostElmSize = (ghostElm, width, height) => {
  9088. setSizeProp(ghostElm, 'width', width);
  9089. setSizeProp(ghostElm, 'height', height);
  9090. };
  9091. const resizeGhostElement = e => {
  9092. let deltaX, deltaY, proportional;
  9093. let resizeHelperX, resizeHelperY;
  9094. deltaX = e.screenX - startX;
  9095. deltaY = e.screenY - startY;
  9096. width = deltaX * selectedHandle[2] + startW;
  9097. height = deltaY * selectedHandle[3] + startH;
  9098. width = width < 5 ? 5 : width;
  9099. height = height < 5 ? 5 : height;
  9100. if ((isImage(selectedElm) || isMedia(selectedElm)) && getResizeImgProportional(editor) !== false) {
  9101. proportional = !VK.modifierPressed(e);
  9102. } else {
  9103. proportional = VK.modifierPressed(e);
  9104. }
  9105. if (proportional) {
  9106. if (abs(deltaX) > abs(deltaY)) {
  9107. height = round$1(width * ratio);
  9108. width = round$1(height / ratio);
  9109. } else {
  9110. width = round$1(height / ratio);
  9111. height = round$1(width * ratio);
  9112. }
  9113. }
  9114. setGhostElmSize(selectedElmGhost, width, height);
  9115. resizeHelperX = selectedHandle.startPos.x + deltaX;
  9116. resizeHelperY = selectedHandle.startPos.y + deltaY;
  9117. resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0;
  9118. resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0;
  9119. dom.setStyles(resizeHelper, {
  9120. left: resizeHelperX,
  9121. top: resizeHelperY,
  9122. display: 'block'
  9123. });
  9124. resizeHelper.innerHTML = width + ' &times; ' + height;
  9125. if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) {
  9126. dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width));
  9127. }
  9128. if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) {
  9129. dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height));
  9130. }
  9131. deltaX = rootElement.scrollWidth - startScrollWidth;
  9132. deltaY = rootElement.scrollHeight - startScrollHeight;
  9133. if (deltaX + deltaY !== 0) {
  9134. dom.setStyles(resizeHelper, {
  9135. left: resizeHelperX - deltaX,
  9136. top: resizeHelperY - deltaY
  9137. });
  9138. }
  9139. if (!resizeStarted) {
  9140. fireObjectResizeStart(editor, selectedElm, startW, startH, 'corner-' + selectedHandle.name);
  9141. resizeStarted = true;
  9142. }
  9143. };
  9144. const endGhostResize = () => {
  9145. const wasResizeStarted = resizeStarted;
  9146. resizeStarted = false;
  9147. if (wasResizeStarted) {
  9148. setSizeProp(selectedElm, 'width', width);
  9149. setSizeProp(selectedElm, 'height', height);
  9150. }
  9151. dom.unbind(editableDoc, 'mousemove', resizeGhostElement);
  9152. dom.unbind(editableDoc, 'mouseup', endGhostResize);
  9153. if (rootDocument !== editableDoc) {
  9154. dom.unbind(rootDocument, 'mousemove', resizeGhostElement);
  9155. dom.unbind(rootDocument, 'mouseup', endGhostResize);
  9156. }
  9157. dom.remove(selectedElmGhost);
  9158. dom.remove(resizeHelper);
  9159. dom.remove(resizeBackdrop);
  9160. showResizeRect(selectedElm);
  9161. if (wasResizeStarted) {
  9162. fireObjectResized(editor, selectedElm, width, height, 'corner-' + selectedHandle.name);
  9163. dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style'));
  9164. }
  9165. editor.nodeChanged();
  9166. };
  9167. const showResizeRect = targetElm => {
  9168. unbindResizeHandleEvents();
  9169. const position = dom.getPos(targetElm, rootElement);
  9170. const selectedElmX = position.x;
  9171. const selectedElmY = position.y;
  9172. const rect = targetElm.getBoundingClientRect();
  9173. const targetWidth = rect.width || rect.right - rect.left;
  9174. const targetHeight = rect.height || rect.bottom - rect.top;
  9175. if (selectedElm !== targetElm) {
  9176. hideResizeRect();
  9177. selectedElm = targetElm;
  9178. width = height = 0;
  9179. }
  9180. const e = editor.dispatch('ObjectSelected', { target: targetElm });
  9181. if (isResizable(targetElm) && !e.isDefaultPrevented()) {
  9182. each$d(resizeHandles, (handle, name) => {
  9183. const startDrag = e => {
  9184. const target = getResizeTargets(selectedElm)[0];
  9185. startX = e.screenX;
  9186. startY = e.screenY;
  9187. startW = target.clientWidth;
  9188. startH = target.clientHeight;
  9189. ratio = startH / startW;
  9190. selectedHandle = handle;
  9191. selectedHandle.name = name;
  9192. selectedHandle.startPos = {
  9193. x: targetWidth * handle[0] + selectedElmX,
  9194. y: targetHeight * handle[1] + selectedElmY
  9195. };
  9196. startScrollWidth = rootElement.scrollWidth;
  9197. startScrollHeight = rootElement.scrollHeight;
  9198. resizeBackdrop = dom.add(rootElement, 'div', {
  9199. 'class': 'mce-resize-backdrop',
  9200. 'data-mce-bogus': 'all'
  9201. });
  9202. dom.setStyles(resizeBackdrop, {
  9203. position: 'fixed',
  9204. left: '0',
  9205. top: '0',
  9206. width: '100%',
  9207. height: '100%'
  9208. });
  9209. selectedElmGhost = createGhostElement(selectedElm);
  9210. dom.addClass(selectedElmGhost, 'mce-clonedresizable');
  9211. dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all');
  9212. selectedElmGhost.contentEditable = 'false';
  9213. dom.setStyles(selectedElmGhost, {
  9214. left: selectedElmX,
  9215. top: selectedElmY,
  9216. margin: 0
  9217. });
  9218. setGhostElmSize(selectedElmGhost, targetWidth, targetHeight);
  9219. selectedElmGhost.removeAttribute(elementSelectionAttr);
  9220. rootElement.appendChild(selectedElmGhost);
  9221. dom.bind(editableDoc, 'mousemove', resizeGhostElement);
  9222. dom.bind(editableDoc, 'mouseup', endGhostResize);
  9223. if (rootDocument !== editableDoc) {
  9224. dom.bind(rootDocument, 'mousemove', resizeGhostElement);
  9225. dom.bind(rootDocument, 'mouseup', endGhostResize);
  9226. }
  9227. resizeHelper = dom.add(rootElement, 'div', {
  9228. 'class': 'mce-resize-helper',
  9229. 'data-mce-bogus': 'all'
  9230. }, startW + ' &times; ' + startH);
  9231. };
  9232. let handleElm = dom.get('mceResizeHandle' + name);
  9233. if (handleElm) {
  9234. dom.remove(handleElm);
  9235. }
  9236. handleElm = dom.add(rootElement, 'div', {
  9237. 'id': 'mceResizeHandle' + name,
  9238. 'data-mce-bogus': 'all',
  9239. 'class': 'mce-resizehandle',
  9240. 'unselectable': true,
  9241. 'style': 'cursor:' + name + '-resize; margin:0; padding:0'
  9242. });
  9243. dom.bind(handleElm, 'mousedown', e => {
  9244. e.stopImmediatePropagation();
  9245. e.preventDefault();
  9246. startDrag(e);
  9247. });
  9248. handle.elm = handleElm;
  9249. dom.setStyles(handleElm, {
  9250. left: targetWidth * handle[0] + selectedElmX - handleElm.offsetWidth / 2,
  9251. top: targetHeight * handle[1] + selectedElmY - handleElm.offsetHeight / 2
  9252. });
  9253. });
  9254. } else {
  9255. hideResizeRect(false);
  9256. }
  9257. };
  9258. const throttledShowResizeRect = first$1(showResizeRect, 0);
  9259. const hideResizeRect = (removeSelected = true) => {
  9260. throttledShowResizeRect.cancel();
  9261. unbindResizeHandleEvents();
  9262. if (selectedElm && removeSelected) {
  9263. selectedElm.removeAttribute(elementSelectionAttr);
  9264. }
  9265. each$d(resizeHandles, (value, name) => {
  9266. const handleElm = dom.get('mceResizeHandle' + name);
  9267. if (handleElm) {
  9268. dom.unbind(handleElm);
  9269. dom.remove(handleElm);
  9270. }
  9271. });
  9272. };
  9273. const isChildOrEqual = (node, parent) => dom.isChildOf(node, parent);
  9274. const updateResizeRect = e => {
  9275. if (resizeStarted || editor.removed || editor.composing) {
  9276. return;
  9277. }
  9278. const targetElm = e.type === 'mousedown' ? e.target : selection.getNode();
  9279. const controlElm = closest$3(SugarElement.fromDom(targetElm), controlElmSelector).map(e => e.dom).getOrUndefined();
  9280. const selectedValue = isNonNullable(controlElm) ? dom.getAttrib(controlElm, elementSelectionAttr, '1') : '1';
  9281. each$e(dom.select(`img[${ elementSelectionAttr }],hr[${ elementSelectionAttr }]`), img => {
  9282. img.removeAttribute(elementSelectionAttr);
  9283. });
  9284. if (isNonNullable(controlElm) && isChildOrEqual(controlElm, rootElement)) {
  9285. disableGeckoResize();
  9286. const startElm = selection.getStart(true);
  9287. if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) {
  9288. dom.setAttrib(controlElm, elementSelectionAttr, selectedValue);
  9289. throttledShowResizeRect.throttle(controlElm);
  9290. return;
  9291. }
  9292. }
  9293. hideResizeRect();
  9294. };
  9295. const unbindResizeHandleEvents = () => {
  9296. each$d(resizeHandles, handle => {
  9297. if (handle.elm) {
  9298. dom.unbind(handle.elm);
  9299. delete handle.elm;
  9300. }
  9301. });
  9302. };
  9303. const disableGeckoResize = () => {
  9304. try {
  9305. editor.getDoc().execCommand('enableObjectResizing', false, 'false');
  9306. } catch (ex) {
  9307. }
  9308. };
  9309. editor.on('init', () => {
  9310. disableGeckoResize();
  9311. editor.on('NodeChange ResizeEditor ResizeWindow ResizeContent drop', updateResizeRect);
  9312. editor.on('keyup compositionend', e => {
  9313. if (selectedElm && selectedElm.nodeName === 'TABLE') {
  9314. updateResizeRect(e);
  9315. }
  9316. });
  9317. editor.on('hide blur', hideResizeRect);
  9318. editor.on('contextmenu longpress', contextMenuSelectImage, true);
  9319. });
  9320. editor.on('remove', unbindResizeHandleEvents);
  9321. const destroy = () => {
  9322. throttledShowResizeRect.cancel();
  9323. selectedElm = selectedElmGhost = resizeBackdrop = null;
  9324. };
  9325. return {
  9326. isResizable,
  9327. showResizeRect,
  9328. hideResizeRect,
  9329. updateResizeRect,
  9330. destroy
  9331. };
  9332. };
  9333. const setStart = (rng, situ) => {
  9334. situ.fold(e => {
  9335. rng.setStartBefore(e.dom);
  9336. }, (e, o) => {
  9337. rng.setStart(e.dom, o);
  9338. }, e => {
  9339. rng.setStartAfter(e.dom);
  9340. });
  9341. };
  9342. const setFinish = (rng, situ) => {
  9343. situ.fold(e => {
  9344. rng.setEndBefore(e.dom);
  9345. }, (e, o) => {
  9346. rng.setEnd(e.dom, o);
  9347. }, e => {
  9348. rng.setEndAfter(e.dom);
  9349. });
  9350. };
  9351. const relativeToNative = (win, startSitu, finishSitu) => {
  9352. const range = win.document.createRange();
  9353. setStart(range, startSitu);
  9354. setFinish(range, finishSitu);
  9355. return range;
  9356. };
  9357. const exactToNative = (win, start, soffset, finish, foffset) => {
  9358. const rng = win.document.createRange();
  9359. rng.setStart(start.dom, soffset);
  9360. rng.setEnd(finish.dom, foffset);
  9361. return rng;
  9362. };
  9363. const adt$3 = Adt.generate([
  9364. {
  9365. ltr: [
  9366. 'start',
  9367. 'soffset',
  9368. 'finish',
  9369. 'foffset'
  9370. ]
  9371. },
  9372. {
  9373. rtl: [
  9374. 'start',
  9375. 'soffset',
  9376. 'finish',
  9377. 'foffset'
  9378. ]
  9379. }
  9380. ]);
  9381. const fromRange = (win, type, range) => type(SugarElement.fromDom(range.startContainer), range.startOffset, SugarElement.fromDom(range.endContainer), range.endOffset);
  9382. const getRanges = (win, selection) => selection.match({
  9383. domRange: rng => {
  9384. return {
  9385. ltr: constant(rng),
  9386. rtl: Optional.none
  9387. };
  9388. },
  9389. relative: (startSitu, finishSitu) => {
  9390. return {
  9391. ltr: cached(() => relativeToNative(win, startSitu, finishSitu)),
  9392. rtl: cached(() => Optional.some(relativeToNative(win, finishSitu, startSitu)))
  9393. };
  9394. },
  9395. exact: (start, soffset, finish, foffset) => {
  9396. return {
  9397. ltr: cached(() => exactToNative(win, start, soffset, finish, foffset)),
  9398. rtl: cached(() => Optional.some(exactToNative(win, finish, foffset, start, soffset)))
  9399. };
  9400. }
  9401. });
  9402. const doDiagnose = (win, ranges) => {
  9403. const rng = ranges.ltr();
  9404. if (rng.collapsed) {
  9405. const reversed = ranges.rtl().filter(rev => rev.collapsed === false);
  9406. return reversed.map(rev => adt$3.rtl(SugarElement.fromDom(rev.endContainer), rev.endOffset, SugarElement.fromDom(rev.startContainer), rev.startOffset)).getOrThunk(() => fromRange(win, adt$3.ltr, rng));
  9407. } else {
  9408. return fromRange(win, adt$3.ltr, rng);
  9409. }
  9410. };
  9411. const diagnose = (win, selection) => {
  9412. const ranges = getRanges(win, selection);
  9413. return doDiagnose(win, ranges);
  9414. };
  9415. adt$3.ltr;
  9416. adt$3.rtl;
  9417. const create$a = (start, soffset, finish, foffset) => ({
  9418. start,
  9419. soffset,
  9420. finish,
  9421. foffset
  9422. });
  9423. const SimRange = { create: create$a };
  9424. const caretPositionFromPoint = (doc, x, y) => {
  9425. var _a, _b;
  9426. return Optional.from((_b = (_a = doc.dom).caretPositionFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y)).bind(pos => {
  9427. if (pos.offsetNode === null) {
  9428. return Optional.none();
  9429. }
  9430. const r = doc.dom.createRange();
  9431. r.setStart(pos.offsetNode, pos.offset);
  9432. r.collapse();
  9433. return Optional.some(r);
  9434. });
  9435. };
  9436. const caretRangeFromPoint = (doc, x, y) => {
  9437. var _a, _b;
  9438. return Optional.from((_b = (_a = doc.dom).caretRangeFromPoint) === null || _b === void 0 ? void 0 : _b.call(_a, x, y));
  9439. };
  9440. const availableSearch = (() => {
  9441. if (document.caretPositionFromPoint) {
  9442. return caretPositionFromPoint;
  9443. } else if (document.caretRangeFromPoint) {
  9444. return caretRangeFromPoint;
  9445. } else {
  9446. return Optional.none;
  9447. }
  9448. })();
  9449. const fromPoint$1 = (win, x, y) => {
  9450. const doc = SugarElement.fromDom(win.document);
  9451. return availableSearch(doc, x, y).map(rng => SimRange.create(SugarElement.fromDom(rng.startContainer), rng.startOffset, SugarElement.fromDom(rng.endContainer), rng.endOffset));
  9452. };
  9453. const adt$2 = Adt.generate([
  9454. { before: ['element'] },
  9455. {
  9456. on: [
  9457. 'element',
  9458. 'offset'
  9459. ]
  9460. },
  9461. { after: ['element'] }
  9462. ]);
  9463. const cata = (subject, onBefore, onOn, onAfter) => subject.fold(onBefore, onOn, onAfter);
  9464. const getStart$2 = situ => situ.fold(identity, identity, identity);
  9465. const before$1 = adt$2.before;
  9466. const on = adt$2.on;
  9467. const after$1 = adt$2.after;
  9468. const Situ = {
  9469. before: before$1,
  9470. on,
  9471. after: after$1,
  9472. cata,
  9473. getStart: getStart$2
  9474. };
  9475. const adt$1 = Adt.generate([
  9476. { domRange: ['rng'] },
  9477. {
  9478. relative: [
  9479. 'startSitu',
  9480. 'finishSitu'
  9481. ]
  9482. },
  9483. {
  9484. exact: [
  9485. 'start',
  9486. 'soffset',
  9487. 'finish',
  9488. 'foffset'
  9489. ]
  9490. }
  9491. ]);
  9492. const exactFromRange = simRange => adt$1.exact(simRange.start, simRange.soffset, simRange.finish, simRange.foffset);
  9493. const getStart$1 = selection => selection.match({
  9494. domRange: rng => SugarElement.fromDom(rng.startContainer),
  9495. relative: (startSitu, _finishSitu) => Situ.getStart(startSitu),
  9496. exact: (start, _soffset, _finish, _foffset) => start
  9497. });
  9498. const domRange = adt$1.domRange;
  9499. const relative = adt$1.relative;
  9500. const exact = adt$1.exact;
  9501. const getWin = selection => {
  9502. const start = getStart$1(selection);
  9503. return defaultView(start);
  9504. };
  9505. const range = SimRange.create;
  9506. const SimSelection = {
  9507. domRange,
  9508. relative,
  9509. exact,
  9510. exactFromRange,
  9511. getWin,
  9512. range
  9513. };
  9514. const beforeSpecial = (element, offset) => {
  9515. const name$1 = name(element);
  9516. if ('input' === name$1) {
  9517. return Situ.after(element);
  9518. } else if (!contains$2([
  9519. 'br',
  9520. 'img'
  9521. ], name$1)) {
  9522. return Situ.on(element, offset);
  9523. } else {
  9524. return offset === 0 ? Situ.before(element) : Situ.after(element);
  9525. }
  9526. };
  9527. const preprocessRelative = (startSitu, finishSitu) => {
  9528. const start = startSitu.fold(Situ.before, beforeSpecial, Situ.after);
  9529. const finish = finishSitu.fold(Situ.before, beforeSpecial, Situ.after);
  9530. return SimSelection.relative(start, finish);
  9531. };
  9532. const preprocessExact = (start, soffset, finish, foffset) => {
  9533. const startSitu = beforeSpecial(start, soffset);
  9534. const finishSitu = beforeSpecial(finish, foffset);
  9535. return SimSelection.relative(startSitu, finishSitu);
  9536. };
  9537. const preprocess = selection => selection.match({
  9538. domRange: rng => {
  9539. const start = SugarElement.fromDom(rng.startContainer);
  9540. const finish = SugarElement.fromDom(rng.endContainer);
  9541. return preprocessExact(start, rng.startOffset, finish, rng.endOffset);
  9542. },
  9543. relative: preprocessRelative,
  9544. exact: preprocessExact
  9545. });
  9546. const fromElements = (elements, scope) => {
  9547. const doc = scope || document;
  9548. const fragment = doc.createDocumentFragment();
  9549. each$e(elements, element => {
  9550. fragment.appendChild(element.dom);
  9551. });
  9552. return SugarElement.fromDom(fragment);
  9553. };
  9554. const toNative = selection => {
  9555. const win = SimSelection.getWin(selection).dom;
  9556. const getDomRange = (start, soffset, finish, foffset) => exactToNative(win, start, soffset, finish, foffset);
  9557. const filtered = preprocess(selection);
  9558. return diagnose(win, filtered).match({
  9559. ltr: getDomRange,
  9560. rtl: getDomRange
  9561. });
  9562. };
  9563. const getAtPoint = (win, x, y) => fromPoint$1(win, x, y);
  9564. const fromPoint = (clientX, clientY, doc) => {
  9565. const win = defaultView(SugarElement.fromDom(doc));
  9566. return getAtPoint(win.dom, clientX, clientY).map(simRange => {
  9567. const rng = doc.createRange();
  9568. rng.setStart(simRange.start.dom, simRange.soffset);
  9569. rng.setEnd(simRange.finish.dom, simRange.foffset);
  9570. return rng;
  9571. }).getOrUndefined();
  9572. };
  9573. const isEq$4 = (rng1, rng2) => {
  9574. return isNonNullable(rng1) && isNonNullable(rng2) && (rng1.startContainer === rng2.startContainer && rng1.startOffset === rng2.startOffset) && (rng1.endContainer === rng2.endContainer && rng1.endOffset === rng2.endOffset);
  9575. };
  9576. const findParent = (node, rootNode, predicate) => {
  9577. let currentNode = node;
  9578. while (currentNode && currentNode !== rootNode) {
  9579. if (predicate(currentNode)) {
  9580. return currentNode;
  9581. }
  9582. currentNode = currentNode.parentNode;
  9583. }
  9584. return null;
  9585. };
  9586. const hasParent$1 = (node, rootNode, predicate) => findParent(node, rootNode, predicate) !== null;
  9587. const hasParentWithName = (node, rootNode, name) => hasParent$1(node, rootNode, node => node.nodeName === name);
  9588. const isCeFalseCaretContainer = (node, rootNode) => isCaretContainer$2(node) && !hasParent$1(node, rootNode, isCaretNode);
  9589. const hasBrBeforeAfter = (dom, node, left) => {
  9590. const parentNode = node.parentNode;
  9591. if (parentNode) {
  9592. const walker = new DomTreeWalker(node, dom.getParent(parentNode, dom.isBlock) || dom.getRoot());
  9593. let currentNode;
  9594. while (currentNode = walker[left ? 'prev' : 'next']()) {
  9595. if (isBr$6(currentNode)) {
  9596. return true;
  9597. }
  9598. }
  9599. }
  9600. return false;
  9601. };
  9602. const isPrevNode = (node, name) => {
  9603. var _a;
  9604. return ((_a = node.previousSibling) === null || _a === void 0 ? void 0 : _a.nodeName) === name;
  9605. };
  9606. const hasContentEditableFalseParent = (root, node) => {
  9607. let currentNode = node;
  9608. while (currentNode && currentNode !== root) {
  9609. if (isContentEditableFalse$a(currentNode)) {
  9610. return true;
  9611. }
  9612. currentNode = currentNode.parentNode;
  9613. }
  9614. return false;
  9615. };
  9616. const findTextNodeRelative = (dom, isAfterNode, collapsed, left, startNode) => {
  9617. const body = dom.getRoot();
  9618. const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
  9619. const parentNode = startNode.parentNode;
  9620. let lastInlineElement;
  9621. let node;
  9622. if (!parentNode) {
  9623. return Optional.none();
  9624. }
  9625. const parentBlockContainer = dom.getParent(parentNode, dom.isBlock) || body;
  9626. if (left && isBr$6(startNode) && isAfterNode && dom.isEmpty(parentBlockContainer)) {
  9627. return Optional.some(CaretPosition(parentNode, dom.nodeIndex(startNode)));
  9628. }
  9629. const walker = new DomTreeWalker(startNode, parentBlockContainer);
  9630. while (node = walker[left ? 'prev' : 'next']()) {
  9631. if (dom.getContentEditableParent(node) === 'false' || isCeFalseCaretContainer(node, body)) {
  9632. return Optional.none();
  9633. }
  9634. if (isText$a(node) && node.data.length > 0) {
  9635. if (!hasParentWithName(node, body, 'A')) {
  9636. return Optional.some(CaretPosition(node, left ? node.data.length : 0));
  9637. }
  9638. return Optional.none();
  9639. }
  9640. if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
  9641. return Optional.none();
  9642. }
  9643. lastInlineElement = node;
  9644. }
  9645. if (isComment(lastInlineElement)) {
  9646. return Optional.none();
  9647. }
  9648. if (collapsed && lastInlineElement) {
  9649. return Optional.some(CaretPosition(lastInlineElement, 0));
  9650. }
  9651. return Optional.none();
  9652. };
  9653. const normalizeEndPoint = (dom, collapsed, start, rng) => {
  9654. const body = dom.getRoot();
  9655. let node;
  9656. let normalized = false;
  9657. let container = start ? rng.startContainer : rng.endContainer;
  9658. let offset = start ? rng.startOffset : rng.endOffset;
  9659. const isAfterNode = isElement$6(container) && offset === container.childNodes.length;
  9660. const nonEmptyElementsMap = dom.schema.getNonEmptyElements();
  9661. let directionLeft = start;
  9662. if (isCaretContainer$2(container)) {
  9663. return Optional.none();
  9664. }
  9665. if (isElement$6(container) && offset > container.childNodes.length - 1) {
  9666. directionLeft = false;
  9667. }
  9668. if (isDocument$1(container)) {
  9669. container = body;
  9670. offset = 0;
  9671. }
  9672. if (container === body) {
  9673. if (directionLeft) {
  9674. node = container.childNodes[offset > 0 ? offset - 1 : 0];
  9675. if (node) {
  9676. if (isCaretContainer$2(node)) {
  9677. return Optional.none();
  9678. }
  9679. if (nonEmptyElementsMap[node.nodeName] || isTable$2(node)) {
  9680. return Optional.none();
  9681. }
  9682. }
  9683. }
  9684. if (container.hasChildNodes()) {
  9685. offset = Math.min(!directionLeft && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1);
  9686. container = container.childNodes[offset];
  9687. offset = isText$a(container) && isAfterNode ? container.data.length : 0;
  9688. if (!collapsed && container === body.lastChild && isTable$2(container)) {
  9689. return Optional.none();
  9690. }
  9691. if (hasContentEditableFalseParent(body, container) || isCaretContainer$2(container)) {
  9692. return Optional.none();
  9693. }
  9694. if (container.hasChildNodes() && !isTable$2(container)) {
  9695. node = container;
  9696. const walker = new DomTreeWalker(container, body);
  9697. do {
  9698. if (isContentEditableFalse$a(node) || isCaretContainer$2(node)) {
  9699. normalized = false;
  9700. break;
  9701. }
  9702. if (isText$a(node) && node.data.length > 0) {
  9703. offset = directionLeft ? 0 : node.data.length;
  9704. container = node;
  9705. normalized = true;
  9706. break;
  9707. }
  9708. if (nonEmptyElementsMap[node.nodeName.toLowerCase()] && !isTableCellOrCaption(node)) {
  9709. offset = dom.nodeIndex(node);
  9710. container = node.parentNode;
  9711. if (!directionLeft) {
  9712. offset++;
  9713. }
  9714. normalized = true;
  9715. break;
  9716. }
  9717. } while (node = directionLeft ? walker.next() : walker.prev());
  9718. }
  9719. }
  9720. }
  9721. if (collapsed) {
  9722. if (isText$a(container) && offset === 0) {
  9723. findTextNodeRelative(dom, isAfterNode, collapsed, true, container).each(pos => {
  9724. container = pos.container();
  9725. offset = pos.offset();
  9726. normalized = true;
  9727. });
  9728. }
  9729. if (isElement$6(container)) {
  9730. node = container.childNodes[offset];
  9731. if (!node) {
  9732. node = container.childNodes[offset - 1];
  9733. }
  9734. if (node && isBr$6(node) && !isPrevNode(node, 'A') && !hasBrBeforeAfter(dom, node, false) && !hasBrBeforeAfter(dom, node, true)) {
  9735. findTextNodeRelative(dom, isAfterNode, collapsed, true, node).each(pos => {
  9736. container = pos.container();
  9737. offset = pos.offset();
  9738. normalized = true;
  9739. });
  9740. }
  9741. }
  9742. }
  9743. if (directionLeft && !collapsed && isText$a(container) && offset === container.data.length) {
  9744. findTextNodeRelative(dom, isAfterNode, collapsed, false, container).each(pos => {
  9745. container = pos.container();
  9746. offset = pos.offset();
  9747. normalized = true;
  9748. });
  9749. }
  9750. return normalized && container ? Optional.some(CaretPosition(container, offset)) : Optional.none();
  9751. };
  9752. const normalize$2 = (dom, rng) => {
  9753. const collapsed = rng.collapsed, normRng = rng.cloneRange();
  9754. const startPos = CaretPosition.fromRangeStart(rng);
  9755. normalizeEndPoint(dom, collapsed, true, normRng).each(pos => {
  9756. if (!collapsed || !CaretPosition.isAbove(startPos, pos)) {
  9757. normRng.setStart(pos.container(), pos.offset());
  9758. }
  9759. });
  9760. if (!collapsed) {
  9761. normalizeEndPoint(dom, collapsed, false, normRng).each(pos => {
  9762. normRng.setEnd(pos.container(), pos.offset());
  9763. });
  9764. }
  9765. if (collapsed) {
  9766. normRng.collapse(true);
  9767. }
  9768. return isEq$4(rng, normRng) ? Optional.none() : Optional.some(normRng);
  9769. };
  9770. const splitText = (node, offset) => {
  9771. return node.splitText(offset);
  9772. };
  9773. const split = rng => {
  9774. let startContainer = rng.startContainer, startOffset = rng.startOffset, endContainer = rng.endContainer, endOffset = rng.endOffset;
  9775. if (startContainer === endContainer && isText$a(startContainer)) {
  9776. if (startOffset > 0 && startOffset < startContainer.data.length) {
  9777. endContainer = splitText(startContainer, startOffset);
  9778. startContainer = endContainer.previousSibling;
  9779. if (endOffset > startOffset) {
  9780. endOffset = endOffset - startOffset;
  9781. const newContainer = splitText(endContainer, endOffset).previousSibling;
  9782. startContainer = endContainer = newContainer;
  9783. endOffset = newContainer.data.length;
  9784. startOffset = 0;
  9785. } else {
  9786. endOffset = 0;
  9787. }
  9788. }
  9789. } else {
  9790. if (isText$a(startContainer) && startOffset > 0 && startOffset < startContainer.data.length) {
  9791. startContainer = splitText(startContainer, startOffset);
  9792. startOffset = 0;
  9793. }
  9794. if (isText$a(endContainer) && endOffset > 0 && endOffset < endContainer.data.length) {
  9795. const newContainer = splitText(endContainer, endOffset).previousSibling;
  9796. endContainer = newContainer;
  9797. endOffset = newContainer.data.length;
  9798. }
  9799. }
  9800. return {
  9801. startContainer,
  9802. startOffset,
  9803. endContainer,
  9804. endOffset
  9805. };
  9806. };
  9807. const RangeUtils = dom => {
  9808. const walk = (rng, callback) => {
  9809. return walk$3(dom, rng, callback);
  9810. };
  9811. const split$1 = split;
  9812. const normalize = rng => {
  9813. return normalize$2(dom, rng).fold(never, normalizedRng => {
  9814. rng.setStart(normalizedRng.startContainer, normalizedRng.startOffset);
  9815. rng.setEnd(normalizedRng.endContainer, normalizedRng.endOffset);
  9816. return true;
  9817. });
  9818. };
  9819. const expand = (rng, options = { type: 'word' }) => {
  9820. if (options.type === 'word') {
  9821. const rangeLike = expandRng(dom, rng, [{ inline: 'span' }]);
  9822. const newRange = dom.createRng();
  9823. newRange.setStart(rangeLike.startContainer, rangeLike.startOffset);
  9824. newRange.setEnd(rangeLike.endContainer, rangeLike.endOffset);
  9825. return newRange;
  9826. }
  9827. return rng;
  9828. };
  9829. return {
  9830. walk,
  9831. split: split$1,
  9832. expand,
  9833. normalize
  9834. };
  9835. };
  9836. RangeUtils.compareRanges = isEq$4;
  9837. RangeUtils.getCaretRangeFromPoint = fromPoint;
  9838. RangeUtils.getSelectedNode = getSelectedNode;
  9839. RangeUtils.getNode = getNode$1;
  9840. const Dimension = (name, getOffset) => {
  9841. const set = (element, h) => {
  9842. if (!isNumber(h) && !h.match(/^[0-9]+$/)) {
  9843. throw new Error(name + '.set accepts only positive integer values. Value was ' + h);
  9844. }
  9845. const dom = element.dom;
  9846. if (isSupported$1(dom)) {
  9847. dom.style[name] = h + 'px';
  9848. }
  9849. };
  9850. const get = element => {
  9851. const r = getOffset(element);
  9852. if (r <= 0 || r === null) {
  9853. const css = get$7(element, name);
  9854. return parseFloat(css) || 0;
  9855. }
  9856. return r;
  9857. };
  9858. const getOuter = get;
  9859. const aggregate = (element, properties) => foldl(properties, (acc, property) => {
  9860. const val = get$7(element, property);
  9861. const value = val === undefined ? 0 : parseInt(val, 10);
  9862. return isNaN(value) ? acc : acc + value;
  9863. }, 0);
  9864. const max = (element, value, properties) => {
  9865. const cumulativeInclusions = aggregate(element, properties);
  9866. const absoluteMax = value > cumulativeInclusions ? value - cumulativeInclusions : 0;
  9867. return absoluteMax;
  9868. };
  9869. return {
  9870. set,
  9871. get,
  9872. getOuter,
  9873. aggregate,
  9874. max
  9875. };
  9876. };
  9877. const api = Dimension('height', element => {
  9878. const dom = element.dom;
  9879. return inBody(element) ? dom.getBoundingClientRect().height : dom.offsetHeight;
  9880. });
  9881. const get$2 = element => api.get(element);
  9882. const getDocument = () => SugarElement.fromDom(document);
  9883. const walkUp = (navigation, doc) => {
  9884. const frame = navigation.view(doc);
  9885. return frame.fold(constant([]), f => {
  9886. const parent = navigation.owner(f);
  9887. const rest = walkUp(navigation, parent);
  9888. return [f].concat(rest);
  9889. });
  9890. };
  9891. const pathTo = (element, navigation) => {
  9892. const d = navigation.owner(element);
  9893. return walkUp(navigation, d);
  9894. };
  9895. const view = doc => {
  9896. var _a;
  9897. const element = doc.dom === document ? Optional.none() : Optional.from((_a = doc.dom.defaultView) === null || _a === void 0 ? void 0 : _a.frameElement);
  9898. return element.map(SugarElement.fromDom);
  9899. };
  9900. const owner = element => documentOrOwner(element);
  9901. var Navigation = /*#__PURE__*/Object.freeze({
  9902. __proto__: null,
  9903. view: view,
  9904. owner: owner
  9905. });
  9906. const find = element => {
  9907. const doc = getDocument();
  9908. const scroll = get$5(doc);
  9909. const frames = pathTo(element, Navigation);
  9910. const offset = viewport(element);
  9911. const r = foldr(frames, (b, a) => {
  9912. const loc = viewport(a);
  9913. return {
  9914. left: b.left + loc.left,
  9915. top: b.top + loc.top
  9916. };
  9917. }, {
  9918. left: 0,
  9919. top: 0
  9920. });
  9921. return SugarPosition(r.left + offset.left + scroll.left, r.top + offset.top + scroll.top);
  9922. };
  9923. const excludeFromDescend = element => name(element) === 'textarea';
  9924. const fireScrollIntoViewEvent = (editor, data) => {
  9925. const scrollEvent = editor.dispatch('ScrollIntoView', data);
  9926. return scrollEvent.isDefaultPrevented();
  9927. };
  9928. const fireAfterScrollIntoViewEvent = (editor, data) => {
  9929. editor.dispatch('AfterScrollIntoView', data);
  9930. };
  9931. const descend = (element, offset) => {
  9932. const children = children$1(element);
  9933. if (children.length === 0 || excludeFromDescend(element)) {
  9934. return {
  9935. element,
  9936. offset
  9937. };
  9938. } else if (offset < children.length && !excludeFromDescend(children[offset])) {
  9939. return {
  9940. element: children[offset],
  9941. offset: 0
  9942. };
  9943. } else {
  9944. const last = children[children.length - 1];
  9945. if (excludeFromDescend(last)) {
  9946. return {
  9947. element,
  9948. offset
  9949. };
  9950. } else {
  9951. if (name(last) === 'img') {
  9952. return {
  9953. element: last,
  9954. offset: 1
  9955. };
  9956. } else if (isText$b(last)) {
  9957. return {
  9958. element: last,
  9959. offset: get$3(last).length
  9960. };
  9961. } else {
  9962. return {
  9963. element: last,
  9964. offset: children$1(last).length
  9965. };
  9966. }
  9967. }
  9968. }
  9969. };
  9970. const markerInfo = (element, cleanupFun) => {
  9971. const pos = absolute(element);
  9972. const height = get$2(element);
  9973. return {
  9974. element,
  9975. bottom: pos.top + height,
  9976. height,
  9977. pos,
  9978. cleanup: cleanupFun
  9979. };
  9980. };
  9981. const createMarker$1 = (element, offset) => {
  9982. const startPoint = descend(element, offset);
  9983. const span = SugarElement.fromHtml('<span data-mce-bogus="all" style="display: inline-block;">' + ZWSP$1 + '</span>');
  9984. before$3(startPoint.element, span);
  9985. return markerInfo(span, () => remove$6(span));
  9986. };
  9987. const elementMarker = element => markerInfo(SugarElement.fromDom(element), noop);
  9988. const withMarker = (editor, f, rng, alignToTop) => {
  9989. preserveWith(editor, (_s, _e) => applyWithMarker(editor, f, rng, alignToTop), rng);
  9990. };
  9991. const withScrollEvents = (editor, doc, f, marker, alignToTop) => {
  9992. const data = {
  9993. elm: marker.element.dom,
  9994. alignToTop
  9995. };
  9996. if (fireScrollIntoViewEvent(editor, data)) {
  9997. return;
  9998. }
  9999. const scrollTop = get$5(doc).top;
  10000. f(doc, scrollTop, marker, alignToTop);
  10001. fireAfterScrollIntoViewEvent(editor, data);
  10002. };
  10003. const applyWithMarker = (editor, f, rng, alignToTop) => {
  10004. const body = SugarElement.fromDom(editor.getBody());
  10005. const doc = SugarElement.fromDom(editor.getDoc());
  10006. reflow(body);
  10007. const marker = createMarker$1(SugarElement.fromDom(rng.startContainer), rng.startOffset);
  10008. withScrollEvents(editor, doc, f, marker, alignToTop);
  10009. marker.cleanup();
  10010. };
  10011. const withElement = (editor, element, f, alignToTop) => {
  10012. const doc = SugarElement.fromDom(editor.getDoc());
  10013. withScrollEvents(editor, doc, f, elementMarker(element), alignToTop);
  10014. };
  10015. const preserveWith = (editor, f, rng) => {
  10016. const startElement = rng.startContainer;
  10017. const startOffset = rng.startOffset;
  10018. const endElement = rng.endContainer;
  10019. const endOffset = rng.endOffset;
  10020. f(SugarElement.fromDom(startElement), SugarElement.fromDom(endElement));
  10021. const newRng = editor.dom.createRng();
  10022. newRng.setStart(startElement, startOffset);
  10023. newRng.setEnd(endElement, endOffset);
  10024. editor.selection.setRng(rng);
  10025. };
  10026. const scrollToMarker = (marker, viewHeight, alignToTop, doc) => {
  10027. const pos = marker.pos;
  10028. if (alignToTop) {
  10029. to(pos.left, pos.top, doc);
  10030. } else {
  10031. const y = pos.top - viewHeight + marker.height;
  10032. to(pos.left, y, doc);
  10033. }
  10034. };
  10035. const intoWindowIfNeeded = (doc, scrollTop, viewHeight, marker, alignToTop) => {
  10036. const viewportBottom = viewHeight + scrollTop;
  10037. const markerTop = marker.pos.top;
  10038. const markerBottom = marker.bottom;
  10039. const largerThanViewport = markerBottom - markerTop >= viewHeight;
  10040. if (markerTop < scrollTop) {
  10041. scrollToMarker(marker, viewHeight, alignToTop !== false, doc);
  10042. } else if (markerTop > viewportBottom) {
  10043. const align = largerThanViewport ? alignToTop !== false : alignToTop === true;
  10044. scrollToMarker(marker, viewHeight, align, doc);
  10045. } else if (markerBottom > viewportBottom && !largerThanViewport) {
  10046. scrollToMarker(marker, viewHeight, alignToTop === true, doc);
  10047. }
  10048. };
  10049. const intoWindow = (doc, scrollTop, marker, alignToTop) => {
  10050. const viewHeight = defaultView(doc).dom.innerHeight;
  10051. intoWindowIfNeeded(doc, scrollTop, viewHeight, marker, alignToTop);
  10052. };
  10053. const intoFrame = (doc, scrollTop, marker, alignToTop) => {
  10054. const frameViewHeight = defaultView(doc).dom.innerHeight;
  10055. intoWindowIfNeeded(doc, scrollTop, frameViewHeight, marker, alignToTop);
  10056. const op = find(marker.element);
  10057. const viewportBounds = getBounds(window);
  10058. if (op.top < viewportBounds.y) {
  10059. intoView(marker.element, alignToTop !== false);
  10060. } else if (op.top > viewportBounds.bottom) {
  10061. intoView(marker.element, alignToTop === true);
  10062. }
  10063. };
  10064. const rangeIntoWindow = (editor, rng, alignToTop) => withMarker(editor, intoWindow, rng, alignToTop);
  10065. const elementIntoWindow = (editor, element, alignToTop) => withElement(editor, element, intoWindow, alignToTop);
  10066. const rangeIntoFrame = (editor, rng, alignToTop) => withMarker(editor, intoFrame, rng, alignToTop);
  10067. const elementIntoFrame = (editor, element, alignToTop) => withElement(editor, element, intoFrame, alignToTop);
  10068. const scrollElementIntoView = (editor, element, alignToTop) => {
  10069. const scroller = editor.inline ? elementIntoWindow : elementIntoFrame;
  10070. scroller(editor, element, alignToTop);
  10071. };
  10072. const scrollRangeIntoView = (editor, rng, alignToTop) => {
  10073. const scroller = editor.inline ? rangeIntoWindow : rangeIntoFrame;
  10074. scroller(editor, rng, alignToTop);
  10075. };
  10076. const focus$1 = element => element.dom.focus();
  10077. const hasFocus$1 = element => {
  10078. const root = getRootNode(element).dom;
  10079. return element.dom === root.activeElement;
  10080. };
  10081. const active$1 = (root = getDocument()) => Optional.from(root.dom.activeElement).map(SugarElement.fromDom);
  10082. const search = element => active$1(getRootNode(element)).filter(e => element.dom.contains(e.dom));
  10083. const clamp$1 = (offset, element) => {
  10084. const max = isText$b(element) ? get$3(element).length : children$1(element).length + 1;
  10085. if (offset > max) {
  10086. return max;
  10087. } else if (offset < 0) {
  10088. return 0;
  10089. }
  10090. return offset;
  10091. };
  10092. const normalizeRng = rng => SimSelection.range(rng.start, clamp$1(rng.soffset, rng.start), rng.finish, clamp$1(rng.foffset, rng.finish));
  10093. const isOrContains = (root, elm) => !isRestrictedNode(elm.dom) && (contains(root, elm) || eq(root, elm));
  10094. const isRngInRoot = root => rng => isOrContains(root, rng.start) && isOrContains(root, rng.finish);
  10095. const shouldStore = editor => editor.inline || Env.browser.isFirefox();
  10096. const nativeRangeToSelectionRange = r => SimSelection.range(SugarElement.fromDom(r.startContainer), r.startOffset, SugarElement.fromDom(r.endContainer), r.endOffset);
  10097. const readRange = win => {
  10098. const selection = win.getSelection();
  10099. const rng = !selection || selection.rangeCount === 0 ? Optional.none() : Optional.from(selection.getRangeAt(0));
  10100. return rng.map(nativeRangeToSelectionRange);
  10101. };
  10102. const getBookmark = root => {
  10103. const win = defaultView(root);
  10104. return readRange(win.dom).filter(isRngInRoot(root));
  10105. };
  10106. const validate = (root, bookmark) => Optional.from(bookmark).filter(isRngInRoot(root)).map(normalizeRng);
  10107. const bookmarkToNativeRng = bookmark => {
  10108. const rng = document.createRange();
  10109. try {
  10110. rng.setStart(bookmark.start.dom, bookmark.soffset);
  10111. rng.setEnd(bookmark.finish.dom, bookmark.foffset);
  10112. return Optional.some(rng);
  10113. } catch (_) {
  10114. return Optional.none();
  10115. }
  10116. };
  10117. const store = editor => {
  10118. const newBookmark = shouldStore(editor) ? getBookmark(SugarElement.fromDom(editor.getBody())) : Optional.none();
  10119. editor.bookmark = newBookmark.isSome() ? newBookmark : editor.bookmark;
  10120. };
  10121. const getRng = editor => {
  10122. const bookmark = editor.bookmark ? editor.bookmark : Optional.none();
  10123. return bookmark.bind(x => validate(SugarElement.fromDom(editor.getBody()), x)).bind(bookmarkToNativeRng);
  10124. };
  10125. const restore = editor => {
  10126. getRng(editor).each(rng => editor.selection.setRng(rng));
  10127. };
  10128. const isEditorUIElement$1 = elm => {
  10129. const className = elm.className.toString();
  10130. return className.indexOf('tox-') !== -1 || className.indexOf('mce-') !== -1;
  10131. };
  10132. const FocusManager = { isEditorUIElement: isEditorUIElement$1 };
  10133. const wrappedSetTimeout = (callback, time) => {
  10134. if (!isNumber(time)) {
  10135. time = 0;
  10136. }
  10137. return setTimeout(callback, time);
  10138. };
  10139. const wrappedSetInterval = (callback, time) => {
  10140. if (!isNumber(time)) {
  10141. time = 0;
  10142. }
  10143. return setInterval(callback, time);
  10144. };
  10145. const Delay = {
  10146. setEditorTimeout: (editor, callback, time) => {
  10147. return wrappedSetTimeout(() => {
  10148. if (!editor.removed) {
  10149. callback();
  10150. }
  10151. }, time);
  10152. },
  10153. setEditorInterval: (editor, callback, time) => {
  10154. const timer = wrappedSetInterval(() => {
  10155. if (!editor.removed) {
  10156. callback();
  10157. } else {
  10158. clearInterval(timer);
  10159. }
  10160. }, time);
  10161. return timer;
  10162. }
  10163. };
  10164. const isManualNodeChange = e => {
  10165. return e.type === 'nodechange' && e.selectionChange;
  10166. };
  10167. const registerPageMouseUp = (editor, throttledStore) => {
  10168. const mouseUpPage = () => {
  10169. throttledStore.throttle();
  10170. };
  10171. DOMUtils.DOM.bind(document, 'mouseup', mouseUpPage);
  10172. editor.on('remove', () => {
  10173. DOMUtils.DOM.unbind(document, 'mouseup', mouseUpPage);
  10174. });
  10175. };
  10176. const registerMouseUp = (editor, throttledStore) => {
  10177. editor.on('mouseup touchend', _e => {
  10178. throttledStore.throttle();
  10179. });
  10180. };
  10181. const registerEditorEvents = (editor, throttledStore) => {
  10182. registerMouseUp(editor, throttledStore);
  10183. editor.on('keyup NodeChange AfterSetSelectionRange', e => {
  10184. if (!isManualNodeChange(e)) {
  10185. store(editor);
  10186. }
  10187. });
  10188. };
  10189. const register$6 = editor => {
  10190. const throttledStore = first$1(() => {
  10191. store(editor);
  10192. }, 0);
  10193. editor.on('init', () => {
  10194. if (editor.inline) {
  10195. registerPageMouseUp(editor, throttledStore);
  10196. }
  10197. registerEditorEvents(editor, throttledStore);
  10198. });
  10199. editor.on('remove', () => {
  10200. throttledStore.cancel();
  10201. });
  10202. };
  10203. let documentFocusInHandler;
  10204. const DOM$9 = DOMUtils.DOM;
  10205. const isEditorUIElement = elm => {
  10206. return isElement$6(elm) && FocusManager.isEditorUIElement(elm);
  10207. };
  10208. const isEditorContentAreaElement = elm => {
  10209. const classList = elm.classList;
  10210. if (classList !== undefined) {
  10211. return classList.contains('tox-edit-area') || classList.contains('tox-edit-area__iframe') || classList.contains('mce-content-body');
  10212. } else {
  10213. return false;
  10214. }
  10215. };
  10216. const isUIElement = (editor, elm) => {
  10217. const customSelector = getCustomUiSelector(editor);
  10218. const parent = DOM$9.getParent(elm, elm => {
  10219. return isEditorUIElement(elm) || (customSelector ? editor.dom.is(elm, customSelector) : false);
  10220. });
  10221. return parent !== null;
  10222. };
  10223. const getActiveElement = editor => {
  10224. try {
  10225. const root = getRootNode(SugarElement.fromDom(editor.getElement()));
  10226. return active$1(root).fold(() => document.body, x => x.dom);
  10227. } catch (ex) {
  10228. return document.body;
  10229. }
  10230. };
  10231. const registerEvents$1 = (editorManager, e) => {
  10232. const editor = e.editor;
  10233. register$6(editor);
  10234. editor.on('focusin', () => {
  10235. const focusedEditor = editorManager.focusedEditor;
  10236. if (focusedEditor !== editor) {
  10237. if (focusedEditor) {
  10238. focusedEditor.dispatch('blur', { focusedEditor: editor });
  10239. }
  10240. editorManager.setActive(editor);
  10241. editorManager.focusedEditor = editor;
  10242. editor.dispatch('focus', { blurredEditor: focusedEditor });
  10243. editor.focus(true);
  10244. }
  10245. });
  10246. editor.on('focusout', () => {
  10247. Delay.setEditorTimeout(editor, () => {
  10248. const focusedEditor = editorManager.focusedEditor;
  10249. if (!isUIElement(editor, getActiveElement(editor)) && focusedEditor === editor) {
  10250. editor.dispatch('blur', { focusedEditor: null });
  10251. editorManager.focusedEditor = null;
  10252. }
  10253. });
  10254. });
  10255. if (!documentFocusInHandler) {
  10256. documentFocusInHandler = e => {
  10257. const activeEditor = editorManager.activeEditor;
  10258. if (activeEditor) {
  10259. getOriginalEventTarget(e).each(target => {
  10260. const elem = target;
  10261. if (elem.ownerDocument === document) {
  10262. if (elem !== document.body && !isUIElement(activeEditor, elem) && editorManager.focusedEditor === activeEditor) {
  10263. activeEditor.dispatch('blur', { focusedEditor: null });
  10264. editorManager.focusedEditor = null;
  10265. }
  10266. }
  10267. });
  10268. }
  10269. };
  10270. DOM$9.bind(document, 'focusin', documentFocusInHandler);
  10271. }
  10272. };
  10273. const unregisterDocumentEvents = (editorManager, e) => {
  10274. if (editorManager.focusedEditor === e.editor) {
  10275. editorManager.focusedEditor = null;
  10276. }
  10277. if (!editorManager.activeEditor && documentFocusInHandler) {
  10278. DOM$9.unbind(document, 'focusin', documentFocusInHandler);
  10279. documentFocusInHandler = null;
  10280. }
  10281. };
  10282. const setup$v = editorManager => {
  10283. editorManager.on('AddEditor', curry(registerEvents$1, editorManager));
  10284. editorManager.on('RemoveEditor', curry(unregisterDocumentEvents, editorManager));
  10285. };
  10286. const getContentEditableHost = (editor, node) => editor.dom.getParent(node, node => editor.dom.getContentEditable(node) === 'true');
  10287. const getCollapsedNode = rng => rng.collapsed ? Optional.from(getNode$1(rng.startContainer, rng.startOffset)).map(SugarElement.fromDom) : Optional.none();
  10288. const getFocusInElement = (root, rng) => getCollapsedNode(rng).bind(node => {
  10289. if (isTableSection(node)) {
  10290. return Optional.some(node);
  10291. } else if (!contains(root, node)) {
  10292. return Optional.some(root);
  10293. } else {
  10294. return Optional.none();
  10295. }
  10296. });
  10297. const normalizeSelection = (editor, rng) => {
  10298. getFocusInElement(SugarElement.fromDom(editor.getBody()), rng).bind(elm => {
  10299. return firstPositionIn(elm.dom);
  10300. }).fold(() => {
  10301. editor.selection.normalize();
  10302. }, caretPos => editor.selection.setRng(caretPos.toRange()));
  10303. };
  10304. const focusBody = body => {
  10305. if (body.setActive) {
  10306. try {
  10307. body.setActive();
  10308. } catch (ex) {
  10309. body.focus();
  10310. }
  10311. } else {
  10312. body.focus();
  10313. }
  10314. };
  10315. const hasElementFocus = elm => hasFocus$1(elm) || search(elm).isSome();
  10316. const hasIframeFocus = editor => isNonNullable(editor.iframeElement) && hasFocus$1(SugarElement.fromDom(editor.iframeElement));
  10317. const hasInlineFocus = editor => {
  10318. const rawBody = editor.getBody();
  10319. return rawBody && hasElementFocus(SugarElement.fromDom(rawBody));
  10320. };
  10321. const hasUiFocus = editor => {
  10322. const dos = getRootNode(SugarElement.fromDom(editor.getElement()));
  10323. return active$1(dos).filter(elem => !isEditorContentAreaElement(elem.dom) && isUIElement(editor, elem.dom)).isSome();
  10324. };
  10325. const hasFocus = editor => editor.inline ? hasInlineFocus(editor) : hasIframeFocus(editor);
  10326. const hasEditorOrUiFocus = editor => hasFocus(editor) || hasUiFocus(editor);
  10327. const focusEditor = editor => {
  10328. const selection = editor.selection;
  10329. const body = editor.getBody();
  10330. let rng = selection.getRng();
  10331. editor.quirks.refreshContentEditable();
  10332. if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
  10333. getRng(editor).each(bookmarkRng => {
  10334. editor.selection.setRng(bookmarkRng);
  10335. rng = bookmarkRng;
  10336. });
  10337. }
  10338. const contentEditableHost = getContentEditableHost(editor, selection.getNode());
  10339. if (contentEditableHost && editor.dom.isChildOf(contentEditableHost, body)) {
  10340. focusBody(contentEditableHost);
  10341. normalizeSelection(editor, rng);
  10342. activateEditor(editor);
  10343. return;
  10344. }
  10345. if (!editor.inline) {
  10346. if (!Env.browser.isOpera()) {
  10347. focusBody(body);
  10348. }
  10349. editor.getWin().focus();
  10350. }
  10351. if (Env.browser.isFirefox() || editor.inline) {
  10352. focusBody(body);
  10353. normalizeSelection(editor, rng);
  10354. }
  10355. activateEditor(editor);
  10356. };
  10357. const activateEditor = editor => editor.editorManager.setActive(editor);
  10358. const focus = (editor, skipFocus) => {
  10359. if (editor.removed) {
  10360. return;
  10361. }
  10362. if (skipFocus) {
  10363. activateEditor(editor);
  10364. } else {
  10365. focusEditor(editor);
  10366. }
  10367. };
  10368. const getEndpointElement = (root, rng, start, real, resolve) => {
  10369. const container = start ? rng.startContainer : rng.endContainer;
  10370. const offset = start ? rng.startOffset : rng.endOffset;
  10371. return Optional.from(container).map(SugarElement.fromDom).map(elm => !real || !rng.collapsed ? child$1(elm, resolve(elm, offset)).getOr(elm) : elm).bind(elm => isElement$7(elm) ? Optional.some(elm) : parent(elm).filter(isElement$7)).map(elm => elm.dom).getOr(root);
  10372. };
  10373. const getStart = (root, rng, real = false) => getEndpointElement(root, rng, true, real, (elm, offset) => Math.min(childNodesCount(elm), offset));
  10374. const getEnd$1 = (root, rng, real = false) => getEndpointElement(root, rng, false, real, (elm, offset) => offset > 0 ? offset - 1 : offset);
  10375. const skipEmptyTextNodes = (node, forwards) => {
  10376. const orig = node;
  10377. while (node && isText$a(node) && node.length === 0) {
  10378. node = forwards ? node.nextSibling : node.previousSibling;
  10379. }
  10380. return node || orig;
  10381. };
  10382. const getNode = (root, rng) => {
  10383. if (!rng) {
  10384. return root;
  10385. }
  10386. let startContainer = rng.startContainer;
  10387. let endContainer = rng.endContainer;
  10388. const startOffset = rng.startOffset;
  10389. const endOffset = rng.endOffset;
  10390. let node = rng.commonAncestorContainer;
  10391. if (!rng.collapsed) {
  10392. if (startContainer === endContainer) {
  10393. if (endOffset - startOffset < 2) {
  10394. if (startContainer.hasChildNodes()) {
  10395. node = startContainer.childNodes[startOffset];
  10396. }
  10397. }
  10398. }
  10399. if (isText$a(startContainer) && isText$a(endContainer)) {
  10400. if (startContainer.length === startOffset) {
  10401. startContainer = skipEmptyTextNodes(startContainer.nextSibling, true);
  10402. } else {
  10403. startContainer = startContainer.parentNode;
  10404. }
  10405. if (endOffset === 0) {
  10406. endContainer = skipEmptyTextNodes(endContainer.previousSibling, false);
  10407. } else {
  10408. endContainer = endContainer.parentNode;
  10409. }
  10410. if (startContainer && startContainer === endContainer) {
  10411. node = startContainer;
  10412. }
  10413. }
  10414. }
  10415. const elm = isText$a(node) ? node.parentNode : node;
  10416. return isElement$6(elm) ? elm : root;
  10417. };
  10418. const getSelectedBlocks = (dom, rng, startElm, endElm) => {
  10419. const selectedBlocks = [];
  10420. const root = dom.getRoot();
  10421. const start = dom.getParent(startElm || getStart(root, rng, rng.collapsed), dom.isBlock);
  10422. const end = dom.getParent(endElm || getEnd$1(root, rng, rng.collapsed), dom.isBlock);
  10423. if (start && start !== root) {
  10424. selectedBlocks.push(start);
  10425. }
  10426. if (start && end && start !== end) {
  10427. let node = start;
  10428. const walker = new DomTreeWalker(start, root);
  10429. while ((node = walker.next()) && node !== end) {
  10430. if (dom.isBlock(node)) {
  10431. selectedBlocks.push(node);
  10432. }
  10433. }
  10434. }
  10435. if (end && start !== end && end !== root) {
  10436. selectedBlocks.push(end);
  10437. }
  10438. return selectedBlocks;
  10439. };
  10440. const select = (dom, node, content) => Optional.from(node).bind(node => Optional.from(node.parentNode).map(parent => {
  10441. const idx = dom.nodeIndex(node);
  10442. const rng = dom.createRng();
  10443. rng.setStart(parent, idx);
  10444. rng.setEnd(parent, idx + 1);
  10445. if (content) {
  10446. moveEndPoint(dom, rng, node, true);
  10447. moveEndPoint(dom, rng, node, false);
  10448. }
  10449. return rng;
  10450. }));
  10451. const processRanges = (editor, ranges) => map$3(ranges, range => {
  10452. const evt = editor.dispatch('GetSelectionRange', { range });
  10453. return evt.range !== range ? evt.range : range;
  10454. });
  10455. const getEnd = element => name(element) === 'img' ? 1 : getOption(element).fold(() => children$1(element).length, v => v.length);
  10456. const isTextNodeWithCursorPosition = el => getOption(el).filter(text => text.trim().length !== 0 || text.indexOf(nbsp) > -1).isSome();
  10457. const elementsWithCursorPosition = [
  10458. 'img',
  10459. 'br'
  10460. ];
  10461. const isCursorPosition = elem => {
  10462. const hasCursorPosition = isTextNodeWithCursorPosition(elem);
  10463. return hasCursorPosition || contains$2(elementsWithCursorPosition, name(elem));
  10464. };
  10465. const first = element => descendant$1(element, isCursorPosition);
  10466. const last = element => descendantRtl(element, isCursorPosition);
  10467. const descendantRtl = (scope, predicate) => {
  10468. const descend = element => {
  10469. const children = children$1(element);
  10470. for (let i = children.length - 1; i >= 0; i--) {
  10471. const child = children[i];
  10472. if (predicate(child)) {
  10473. return Optional.some(child);
  10474. }
  10475. const res = descend(child);
  10476. if (res.isSome()) {
  10477. return res;
  10478. }
  10479. }
  10480. return Optional.none();
  10481. };
  10482. return descend(scope);
  10483. };
  10484. const autocompleteSelector = '[data-mce-autocompleter]';
  10485. const create$9 = (editor, range) => {
  10486. if (findIn(SugarElement.fromDom(editor.getBody())).isNone()) {
  10487. const wrapper = SugarElement.fromHtml('<span data-mce-autocompleter="1" data-mce-bogus="1"></span>', editor.getDoc());
  10488. append$1(wrapper, SugarElement.fromDom(range.extractContents()));
  10489. range.insertNode(wrapper.dom);
  10490. parent(wrapper).each(elm => elm.dom.normalize());
  10491. last(wrapper).map(last => {
  10492. editor.selection.setCursorLocation(last.dom, getEnd(last));
  10493. });
  10494. }
  10495. };
  10496. const detect$1 = elm => closest$3(elm, autocompleteSelector);
  10497. const findIn = elm => descendant(elm, autocompleteSelector);
  10498. const remove$3 = (editor, elm) => findIn(elm).each(wrapper => {
  10499. const bookmark = editor.selection.getBookmark();
  10500. unwrap(wrapper);
  10501. editor.selection.moveToBookmark(bookmark);
  10502. });
  10503. const typeLookup = {
  10504. '#text': 3,
  10505. '#comment': 8,
  10506. '#cdata': 4,
  10507. '#pi': 7,
  10508. '#doctype': 10,
  10509. '#document-fragment': 11
  10510. };
  10511. const walk$2 = (node, root, prev) => {
  10512. const startName = prev ? 'lastChild' : 'firstChild';
  10513. const siblingName = prev ? 'prev' : 'next';
  10514. if (node[startName]) {
  10515. return node[startName];
  10516. }
  10517. if (node !== root) {
  10518. let sibling = node[siblingName];
  10519. if (sibling) {
  10520. return sibling;
  10521. }
  10522. for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
  10523. sibling = parent[siblingName];
  10524. if (sibling) {
  10525. return sibling;
  10526. }
  10527. }
  10528. }
  10529. return undefined;
  10530. };
  10531. const isEmptyTextNode = node => {
  10532. var _a;
  10533. const text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
  10534. if (!isWhitespaceText(text)) {
  10535. return false;
  10536. }
  10537. const parentNode = node.parent;
  10538. if (parentNode && (parentNode.name !== 'span' || parentNode.attr('style')) && /^[ ]+$/.test(text)) {
  10539. return false;
  10540. }
  10541. return true;
  10542. };
  10543. const isNonEmptyElement = node => {
  10544. const isNamedAnchor = node.name === 'a' && !node.attr('href') && node.attr('id');
  10545. return node.attr('name') || node.attr('id') && !node.firstChild || node.attr('data-mce-bookmark') || isNamedAnchor;
  10546. };
  10547. class AstNode {
  10548. constructor(name, type) {
  10549. this.name = name;
  10550. this.type = type;
  10551. if (type === 1) {
  10552. this.attributes = [];
  10553. this.attributes.map = {};
  10554. }
  10555. }
  10556. static create(name, attrs) {
  10557. const node = new AstNode(name, typeLookup[name] || 1);
  10558. if (attrs) {
  10559. each$d(attrs, (value, attrName) => {
  10560. node.attr(attrName, value);
  10561. });
  10562. }
  10563. return node;
  10564. }
  10565. replace(node) {
  10566. const self = this;
  10567. if (node.parent) {
  10568. node.remove();
  10569. }
  10570. self.insert(node, self);
  10571. self.remove();
  10572. return self;
  10573. }
  10574. attr(name, value) {
  10575. const self = this;
  10576. if (!isString(name)) {
  10577. if (isNonNullable(name)) {
  10578. each$d(name, (value, key) => {
  10579. self.attr(key, value);
  10580. });
  10581. }
  10582. return self;
  10583. }
  10584. const attrs = self.attributes;
  10585. if (attrs) {
  10586. if (value !== undefined) {
  10587. if (value === null) {
  10588. if (name in attrs.map) {
  10589. delete attrs.map[name];
  10590. let i = attrs.length;
  10591. while (i--) {
  10592. if (attrs[i].name === name) {
  10593. attrs.splice(i, 1);
  10594. return self;
  10595. }
  10596. }
  10597. }
  10598. return self;
  10599. }
  10600. if (name in attrs.map) {
  10601. let i = attrs.length;
  10602. while (i--) {
  10603. if (attrs[i].name === name) {
  10604. attrs[i].value = value;
  10605. break;
  10606. }
  10607. }
  10608. } else {
  10609. attrs.push({
  10610. name,
  10611. value
  10612. });
  10613. }
  10614. attrs.map[name] = value;
  10615. return self;
  10616. }
  10617. return attrs.map[name];
  10618. }
  10619. return undefined;
  10620. }
  10621. clone() {
  10622. const self = this;
  10623. const clone = new AstNode(self.name, self.type);
  10624. const selfAttrs = self.attributes;
  10625. if (selfAttrs) {
  10626. const cloneAttrs = [];
  10627. cloneAttrs.map = {};
  10628. for (let i = 0, l = selfAttrs.length; i < l; i++) {
  10629. const selfAttr = selfAttrs[i];
  10630. if (selfAttr.name !== 'id') {
  10631. cloneAttrs[cloneAttrs.length] = {
  10632. name: selfAttr.name,
  10633. value: selfAttr.value
  10634. };
  10635. cloneAttrs.map[selfAttr.name] = selfAttr.value;
  10636. }
  10637. }
  10638. clone.attributes = cloneAttrs;
  10639. }
  10640. clone.value = self.value;
  10641. return clone;
  10642. }
  10643. wrap(wrapper) {
  10644. const self = this;
  10645. if (self.parent) {
  10646. self.parent.insert(wrapper, self);
  10647. wrapper.append(self);
  10648. }
  10649. return self;
  10650. }
  10651. unwrap() {
  10652. const self = this;
  10653. for (let node = self.firstChild; node;) {
  10654. const next = node.next;
  10655. self.insert(node, self, true);
  10656. node = next;
  10657. }
  10658. self.remove();
  10659. }
  10660. remove() {
  10661. const self = this, parent = self.parent, next = self.next, prev = self.prev;
  10662. if (parent) {
  10663. if (parent.firstChild === self) {
  10664. parent.firstChild = next;
  10665. if (next) {
  10666. next.prev = null;
  10667. }
  10668. } else if (prev) {
  10669. prev.next = next;
  10670. }
  10671. if (parent.lastChild === self) {
  10672. parent.lastChild = prev;
  10673. if (prev) {
  10674. prev.next = null;
  10675. }
  10676. } else if (next) {
  10677. next.prev = prev;
  10678. }
  10679. self.parent = self.next = self.prev = null;
  10680. }
  10681. return self;
  10682. }
  10683. append(node) {
  10684. const self = this;
  10685. if (node.parent) {
  10686. node.remove();
  10687. }
  10688. const last = self.lastChild;
  10689. if (last) {
  10690. last.next = node;
  10691. node.prev = last;
  10692. self.lastChild = node;
  10693. } else {
  10694. self.lastChild = self.firstChild = node;
  10695. }
  10696. node.parent = self;
  10697. return node;
  10698. }
  10699. insert(node, refNode, before) {
  10700. if (node.parent) {
  10701. node.remove();
  10702. }
  10703. const parent = refNode.parent || this;
  10704. if (before) {
  10705. if (refNode === parent.firstChild) {
  10706. parent.firstChild = node;
  10707. } else if (refNode.prev) {
  10708. refNode.prev.next = node;
  10709. }
  10710. node.prev = refNode.prev;
  10711. node.next = refNode;
  10712. refNode.prev = node;
  10713. } else {
  10714. if (refNode === parent.lastChild) {
  10715. parent.lastChild = node;
  10716. } else if (refNode.next) {
  10717. refNode.next.prev = node;
  10718. }
  10719. node.next = refNode.next;
  10720. node.prev = refNode;
  10721. refNode.next = node;
  10722. }
  10723. node.parent = parent;
  10724. return node;
  10725. }
  10726. getAll(name) {
  10727. const self = this;
  10728. const collection = [];
  10729. for (let node = self.firstChild; node; node = walk$2(node, self)) {
  10730. if (node.name === name) {
  10731. collection.push(node);
  10732. }
  10733. }
  10734. return collection;
  10735. }
  10736. children() {
  10737. const self = this;
  10738. const collection = [];
  10739. for (let node = self.firstChild; node; node = node.next) {
  10740. collection.push(node);
  10741. }
  10742. return collection;
  10743. }
  10744. empty() {
  10745. const self = this;
  10746. if (self.firstChild) {
  10747. const nodes = [];
  10748. for (let node = self.firstChild; node; node = walk$2(node, self)) {
  10749. nodes.push(node);
  10750. }
  10751. let i = nodes.length;
  10752. while (i--) {
  10753. const node = nodes[i];
  10754. node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
  10755. }
  10756. }
  10757. self.firstChild = self.lastChild = null;
  10758. return self;
  10759. }
  10760. isEmpty(elements, whitespace = {}, predicate) {
  10761. var _a;
  10762. const self = this;
  10763. let node = self.firstChild;
  10764. if (isNonEmptyElement(self)) {
  10765. return false;
  10766. }
  10767. if (node) {
  10768. do {
  10769. if (node.type === 1) {
  10770. if (node.attr('data-mce-bogus')) {
  10771. continue;
  10772. }
  10773. if (elements[node.name]) {
  10774. return false;
  10775. }
  10776. if (isNonEmptyElement(node)) {
  10777. return false;
  10778. }
  10779. }
  10780. if (node.type === 8) {
  10781. return false;
  10782. }
  10783. if (node.type === 3 && !isEmptyTextNode(node)) {
  10784. return false;
  10785. }
  10786. if (node.type === 3 && node.parent && whitespace[node.parent.name] && isWhitespaceText((_a = node.value) !== null && _a !== void 0 ? _a : '')) {
  10787. return false;
  10788. }
  10789. if (predicate && predicate(node)) {
  10790. return false;
  10791. }
  10792. } while (node = walk$2(node, self));
  10793. }
  10794. return true;
  10795. }
  10796. walk(prev) {
  10797. return walk$2(this, null, prev);
  10798. }
  10799. }
  10800. const isConditionalComment = (html, startIndex) => /^\s*\[if [\w\W]+\]>.*<!\[endif\](--!?)?>/.test(html.substr(startIndex));
  10801. const findCommentEndIndex = (html, isBogus, startIndex = 0) => {
  10802. const lcHtml = html.toLowerCase();
  10803. if (lcHtml.indexOf('[if ', startIndex) !== -1 && isConditionalComment(lcHtml, startIndex)) {
  10804. const endIfIndex = lcHtml.indexOf('[endif]', startIndex);
  10805. return lcHtml.indexOf('>', endIfIndex);
  10806. } else {
  10807. if (isBogus) {
  10808. const endIndex = lcHtml.indexOf('>', startIndex);
  10809. return endIndex !== -1 ? endIndex : lcHtml.length;
  10810. } else {
  10811. const endCommentRegexp = /--!?>/g;
  10812. endCommentRegexp.lastIndex = startIndex;
  10813. const match = endCommentRegexp.exec(html);
  10814. return match ? match.index + match[0].length : lcHtml.length;
  10815. }
  10816. }
  10817. };
  10818. const findMatchingEndTagIndex = (schema, html, startIndex) => {
  10819. const startTagRegExp = /<([!?\/])?([A-Za-z0-9\-_:.]+)/g;
  10820. const endTagRegExp = /(?:\s(?:[^'">]+(?:"[^"]*"|'[^']*'))*[^"'>]*(?:"[^">]*|'[^'>]*)?|\s*|\/)>/g;
  10821. const voidElements = schema.getVoidElements();
  10822. let count = 1, index = startIndex;
  10823. while (count !== 0) {
  10824. startTagRegExp.lastIndex = index;
  10825. while (true) {
  10826. const startMatch = startTagRegExp.exec(html);
  10827. if (startMatch === null) {
  10828. return index;
  10829. } else if (startMatch[1] === '!') {
  10830. if (startsWith(startMatch[2], '--')) {
  10831. index = findCommentEndIndex(html, false, startMatch.index + '!--'.length);
  10832. } else {
  10833. index = findCommentEndIndex(html, true, startMatch.index + 1);
  10834. }
  10835. break;
  10836. } else {
  10837. endTagRegExp.lastIndex = startTagRegExp.lastIndex;
  10838. const endMatch = endTagRegExp.exec(html);
  10839. if (isNull(endMatch) || endMatch.index !== startTagRegExp.lastIndex) {
  10840. continue;
  10841. }
  10842. if (startMatch[1] === '/') {
  10843. count -= 1;
  10844. } else if (!has$2(voidElements, startMatch[2])) {
  10845. count += 1;
  10846. }
  10847. index = startTagRegExp.lastIndex + endMatch[0].length;
  10848. break;
  10849. }
  10850. }
  10851. }
  10852. return index;
  10853. };
  10854. const trimHtml$1 = (tempAttrs, html) => {
  10855. const trimContentRegExp = new RegExp(['\\s?(' + tempAttrs.join('|') + ')="[^"]+"'].join('|'), 'gi');
  10856. return html.replace(trimContentRegExp, '');
  10857. };
  10858. const trimInternal = (serializer, html) => {
  10859. const bogusAllRegExp = /<(\w+) [^>]*data-mce-bogus="all"[^>]*>/g;
  10860. const schema = serializer.schema;
  10861. let content = trimHtml$1(serializer.getTempAttrs(), html);
  10862. const voidElements = schema.getVoidElements();
  10863. let matches;
  10864. while (matches = bogusAllRegExp.exec(content)) {
  10865. const index = bogusAllRegExp.lastIndex;
  10866. const matchLength = matches[0].length;
  10867. let endTagIndex;
  10868. if (voidElements[matches[1]]) {
  10869. endTagIndex = index;
  10870. } else {
  10871. endTagIndex = findMatchingEndTagIndex(schema, content, index);
  10872. }
  10873. content = content.substring(0, index - matchLength) + content.substring(endTagIndex);
  10874. bogusAllRegExp.lastIndex = index - matchLength;
  10875. }
  10876. return trim$1(content);
  10877. };
  10878. const trimExternal = trimInternal;
  10879. const cleanupBogusElements = parent => {
  10880. const bogusElements = descendants(parent, '[data-mce-bogus]');
  10881. each$e(bogusElements, elem => {
  10882. const bogusValue = get$9(elem, 'data-mce-bogus');
  10883. if (bogusValue === 'all') {
  10884. remove$6(elem);
  10885. } else if (isBr$5(elem)) {
  10886. before$3(elem, SugarElement.fromText(zeroWidth));
  10887. remove$6(elem);
  10888. } else {
  10889. unwrap(elem);
  10890. }
  10891. });
  10892. };
  10893. const cleanupInputNames = parent => {
  10894. const inputs = descendants(parent, 'input');
  10895. each$e(inputs, input => {
  10896. remove$b(input, 'name');
  10897. });
  10898. };
  10899. const trimEmptyContents = (editor, html) => {
  10900. const blockName = getForcedRootBlock(editor);
  10901. const emptyRegExp = new RegExp(`^(<${ blockName }[^>]*>(&nbsp;|&#160;|\\s|\u00a0|<br \\/>|)<\\/${ blockName }>[\r\n]*|<br \\/>[\r\n]*)$`);
  10902. return html.replace(emptyRegExp, '');
  10903. };
  10904. const getPlainTextContent = (editor, body) => {
  10905. const doc = editor.getDoc();
  10906. const dos = getRootNode(SugarElement.fromDom(editor.getBody()));
  10907. const offscreenDiv = SugarElement.fromTag('div', doc);
  10908. set$2(offscreenDiv, 'data-mce-bogus', 'all');
  10909. setAll(offscreenDiv, {
  10910. position: 'fixed',
  10911. left: '-9999999px',
  10912. top: '0'
  10913. });
  10914. set(offscreenDiv, body.innerHTML);
  10915. cleanupBogusElements(offscreenDiv);
  10916. cleanupInputNames(offscreenDiv);
  10917. const root = getContentContainer(dos);
  10918. append$1(root, offscreenDiv);
  10919. const content = trim$1(offscreenDiv.dom.innerText);
  10920. remove$6(offscreenDiv);
  10921. return content;
  10922. };
  10923. const getContentFromBody = (editor, args, body) => {
  10924. let content;
  10925. if (args.format === 'raw') {
  10926. content = Tools.trim(trimExternal(editor.serializer, body.innerHTML));
  10927. } else if (args.format === 'text') {
  10928. content = getPlainTextContent(editor, body);
  10929. } else if (args.format === 'tree') {
  10930. content = editor.serializer.serialize(body, args);
  10931. } else {
  10932. content = trimEmptyContents(editor, editor.serializer.serialize(body, args));
  10933. }
  10934. const shouldTrim = args.format !== 'text' && !isWsPreserveElement(SugarElement.fromDom(body));
  10935. return shouldTrim && isString(content) ? Tools.trim(content) : content;
  10936. };
  10937. const getContentInternal = (editor, args) => Optional.from(editor.getBody()).fold(constant(args.format === 'tree' ? new AstNode('body', 11) : ''), body => getContentFromBody(editor, args, body));
  10938. const makeMap$1 = Tools.makeMap;
  10939. const Writer = settings => {
  10940. const html = [];
  10941. settings = settings || {};
  10942. const indent = settings.indent;
  10943. const indentBefore = makeMap$1(settings.indent_before || '');
  10944. const indentAfter = makeMap$1(settings.indent_after || '');
  10945. const encode = Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
  10946. const htmlOutput = settings.element_format !== 'xhtml';
  10947. return {
  10948. start: (name, attrs, empty) => {
  10949. if (indent && indentBefore[name] && html.length > 0) {
  10950. const value = html[html.length - 1];
  10951. if (value.length > 0 && value !== '\n') {
  10952. html.push('\n');
  10953. }
  10954. }
  10955. html.push('<', name);
  10956. if (attrs) {
  10957. for (let i = 0, l = attrs.length; i < l; i++) {
  10958. const attr = attrs[i];
  10959. html.push(' ', attr.name, '="', encode(attr.value, true), '"');
  10960. }
  10961. }
  10962. if (!empty || htmlOutput) {
  10963. html[html.length] = '>';
  10964. } else {
  10965. html[html.length] = ' />';
  10966. }
  10967. if (empty && indent && indentAfter[name] && html.length > 0) {
  10968. const value = html[html.length - 1];
  10969. if (value.length > 0 && value !== '\n') {
  10970. html.push('\n');
  10971. }
  10972. }
  10973. },
  10974. end: name => {
  10975. let value;
  10976. html.push('</', name, '>');
  10977. if (indent && indentAfter[name] && html.length > 0) {
  10978. value = html[html.length - 1];
  10979. if (value.length > 0 && value !== '\n') {
  10980. html.push('\n');
  10981. }
  10982. }
  10983. },
  10984. text: (text, raw) => {
  10985. if (text.length > 0) {
  10986. html[html.length] = raw ? text : encode(text);
  10987. }
  10988. },
  10989. cdata: text => {
  10990. html.push('<![CDATA[', text, ']]>');
  10991. },
  10992. comment: text => {
  10993. html.push('<!--', text, '-->');
  10994. },
  10995. pi: (name, text) => {
  10996. if (text) {
  10997. html.push('<?', name, ' ', encode(text), '?>');
  10998. } else {
  10999. html.push('<?', name, '?>');
  11000. }
  11001. if (indent) {
  11002. html.push('\n');
  11003. }
  11004. },
  11005. doctype: text => {
  11006. html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
  11007. },
  11008. reset: () => {
  11009. html.length = 0;
  11010. },
  11011. getContent: () => {
  11012. return html.join('').replace(/\n$/, '');
  11013. }
  11014. };
  11015. };
  11016. const HtmlSerializer = (settings = {}, schema = Schema()) => {
  11017. const writer = Writer(settings);
  11018. settings.validate = 'validate' in settings ? settings.validate : true;
  11019. const serialize = node => {
  11020. const validate = settings.validate;
  11021. const handlers = {
  11022. 3: node => {
  11023. var _a;
  11024. writer.text((_a = node.value) !== null && _a !== void 0 ? _a : '', node.raw);
  11025. },
  11026. 8: node => {
  11027. var _a;
  11028. writer.comment((_a = node.value) !== null && _a !== void 0 ? _a : '');
  11029. },
  11030. 7: node => {
  11031. writer.pi(node.name, node.value);
  11032. },
  11033. 10: node => {
  11034. var _a;
  11035. writer.doctype((_a = node.value) !== null && _a !== void 0 ? _a : '');
  11036. },
  11037. 4: node => {
  11038. var _a;
  11039. writer.cdata((_a = node.value) !== null && _a !== void 0 ? _a : '');
  11040. },
  11041. 11: node => {
  11042. let tempNode = node;
  11043. if (tempNode = tempNode.firstChild) {
  11044. do {
  11045. walk(tempNode);
  11046. } while (tempNode = tempNode.next);
  11047. }
  11048. }
  11049. };
  11050. writer.reset();
  11051. const walk = node => {
  11052. var _a;
  11053. const handler = handlers[node.type];
  11054. if (!handler) {
  11055. const name = node.name;
  11056. const isEmpty = name in schema.getVoidElements();
  11057. let attrs = node.attributes;
  11058. if (validate && attrs && attrs.length > 1) {
  11059. const sortedAttrs = [];
  11060. sortedAttrs.map = {};
  11061. const elementRule = schema.getElementRule(node.name);
  11062. if (elementRule) {
  11063. for (let i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
  11064. const attrName = elementRule.attributesOrder[i];
  11065. if (attrName in attrs.map) {
  11066. const attrValue = attrs.map[attrName];
  11067. sortedAttrs.map[attrName] = attrValue;
  11068. sortedAttrs.push({
  11069. name: attrName,
  11070. value: attrValue
  11071. });
  11072. }
  11073. }
  11074. for (let i = 0, l = attrs.length; i < l; i++) {
  11075. const attrName = attrs[i].name;
  11076. if (!(attrName in sortedAttrs.map)) {
  11077. const attrValue = attrs.map[attrName];
  11078. sortedAttrs.map[attrName] = attrValue;
  11079. sortedAttrs.push({
  11080. name: attrName,
  11081. value: attrValue
  11082. });
  11083. }
  11084. }
  11085. attrs = sortedAttrs;
  11086. }
  11087. }
  11088. writer.start(name, attrs, isEmpty);
  11089. if (!isEmpty) {
  11090. let child = node.firstChild;
  11091. if (child) {
  11092. if ((name === 'pre' || name === 'textarea') && child.type === 3 && ((_a = child.value) === null || _a === void 0 ? void 0 : _a[0]) === '\n') {
  11093. writer.text('\n', true);
  11094. }
  11095. do {
  11096. walk(child);
  11097. } while (child = child.next);
  11098. }
  11099. writer.end(name);
  11100. }
  11101. } else {
  11102. handler(node);
  11103. }
  11104. };
  11105. if (node.type === 1 && !settings.inner) {
  11106. walk(node);
  11107. } else if (node.type === 3) {
  11108. handlers[3](node);
  11109. } else {
  11110. handlers[11](node);
  11111. }
  11112. return writer.getContent();
  11113. };
  11114. return { serialize };
  11115. };
  11116. const nonInheritableStyles = new Set();
  11117. (() => {
  11118. const nonInheritableStylesArr = [
  11119. 'margin',
  11120. 'margin-left',
  11121. 'margin-right',
  11122. 'margin-top',
  11123. 'margin-bottom',
  11124. 'padding',
  11125. 'padding-left',
  11126. 'padding-right',
  11127. 'padding-top',
  11128. 'padding-bottom',
  11129. 'border',
  11130. 'border-width',
  11131. 'border-style',
  11132. 'border-color',
  11133. 'background',
  11134. 'background-attachment',
  11135. 'background-clip',
  11136. 'background-color',
  11137. 'background-image',
  11138. 'background-origin',
  11139. 'background-position',
  11140. 'background-repeat',
  11141. 'background-size',
  11142. 'float',
  11143. 'position',
  11144. 'left',
  11145. 'right',
  11146. 'top',
  11147. 'bottom',
  11148. 'z-index',
  11149. 'display',
  11150. 'transform',
  11151. 'width',
  11152. 'max-width',
  11153. 'min-width',
  11154. 'height',
  11155. 'max-height',
  11156. 'min-height',
  11157. 'overflow',
  11158. 'overflow-x',
  11159. 'overflow-y',
  11160. 'text-overflow',
  11161. 'vertical-align',
  11162. 'transition',
  11163. 'transition-delay',
  11164. 'transition-duration',
  11165. 'transition-property',
  11166. 'transition-timing-function'
  11167. ];
  11168. each$e(nonInheritableStylesArr, style => {
  11169. nonInheritableStyles.add(style);
  11170. });
  11171. })();
  11172. const shorthandStyleProps = [
  11173. 'font',
  11174. 'text-decoration',
  11175. 'text-emphasis'
  11176. ];
  11177. const getStyleProps = (dom, node) => keys(dom.parseStyle(dom.getAttrib(node, 'style')));
  11178. const isNonInheritableStyle = style => nonInheritableStyles.has(style);
  11179. const hasInheritableStyles = (dom, node) => forall(getStyleProps(dom, node), style => !isNonInheritableStyle(style));
  11180. const getLonghandStyleProps = styles => filter$5(styles, style => exists(shorthandStyleProps, prop => startsWith(style, prop)));
  11181. const hasStyleConflict = (dom, node, parentNode) => {
  11182. const nodeStyleProps = getStyleProps(dom, node);
  11183. const parentNodeStyleProps = getStyleProps(dom, parentNode);
  11184. const valueMismatch = prop => {
  11185. var _a, _b;
  11186. const nodeValue = (_a = dom.getStyle(node, prop)) !== null && _a !== void 0 ? _a : '';
  11187. const parentValue = (_b = dom.getStyle(parentNode, prop)) !== null && _b !== void 0 ? _b : '';
  11188. return isNotEmpty(nodeValue) && isNotEmpty(parentValue) && nodeValue !== parentValue;
  11189. };
  11190. return exists(nodeStyleProps, nodeStyleProp => {
  11191. const propExists = props => exists(props, prop => prop === nodeStyleProp);
  11192. if (!propExists(parentNodeStyleProps) && propExists(shorthandStyleProps)) {
  11193. const longhandProps = getLonghandStyleProps(parentNodeStyleProps);
  11194. return exists(longhandProps, valueMismatch);
  11195. } else {
  11196. return valueMismatch(nodeStyleProp);
  11197. }
  11198. });
  11199. };
  11200. const isChar = (forward, predicate, pos) => Optional.from(pos.container()).filter(isText$a).exists(text => {
  11201. const delta = forward ? 0 : -1;
  11202. return predicate(text.data.charAt(pos.offset() + delta));
  11203. });
  11204. const isBeforeSpace = curry(isChar, true, isWhiteSpace);
  11205. const isAfterSpace = curry(isChar, false, isWhiteSpace);
  11206. const isEmptyText = pos => {
  11207. const container = pos.container();
  11208. return isText$a(container) && (container.data.length === 0 || isZwsp(container.data) && BookmarkManager.isBookmarkNode(container.parentNode));
  11209. };
  11210. const matchesElementPosition = (before, predicate) => pos => getChildNodeAtRelativeOffset(before ? 0 : -1, pos).filter(predicate).isSome();
  11211. const isImageBlock = node => isImg(node) && get$7(SugarElement.fromDom(node), 'display') === 'block';
  11212. const isCefNode = node => isContentEditableFalse$a(node) && !isBogusAll$1(node);
  11213. const isBeforeImageBlock = matchesElementPosition(true, isImageBlock);
  11214. const isAfterImageBlock = matchesElementPosition(false, isImageBlock);
  11215. const isBeforeMedia = matchesElementPosition(true, isMedia$2);
  11216. const isAfterMedia = matchesElementPosition(false, isMedia$2);
  11217. const isBeforeTable = matchesElementPosition(true, isTable$2);
  11218. const isAfterTable = matchesElementPosition(false, isTable$2);
  11219. const isBeforeContentEditableFalse = matchesElementPosition(true, isCefNode);
  11220. const isAfterContentEditableFalse = matchesElementPosition(false, isCefNode);
  11221. const dropLast = xs => xs.slice(0, -1);
  11222. const parentsUntil = (start, root, predicate) => {
  11223. if (contains(root, start)) {
  11224. return dropLast(parents$1(start, elm => {
  11225. return predicate(elm) || eq(elm, root);
  11226. }));
  11227. } else {
  11228. return [];
  11229. }
  11230. };
  11231. const parents = (start, root) => parentsUntil(start, root, never);
  11232. const parentsAndSelf = (start, root) => [start].concat(parents(start, root));
  11233. const navigateIgnoreEmptyTextNodes = (forward, root, from) => navigateIgnore(forward, root, from, isEmptyText);
  11234. const getClosestBlock$1 = (root, pos) => find$2(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
  11235. const isAtBeforeAfterBlockBoundary = (forward, root, pos) => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => getClosestBlock$1(root, pos).fold(() => !isInSameBlock(newPos, pos, root.dom), fromBlock => !isInSameBlock(newPos, pos, root.dom) && contains(fromBlock, SugarElement.fromDom(newPos.container()))));
  11236. const isAtBlockBoundary = (forward, root, pos) => getClosestBlock$1(root, pos).fold(() => navigateIgnoreEmptyTextNodes(forward, root.dom, pos).forall(newPos => !isInSameBlock(newPos, pos, root.dom)), parent => navigateIgnoreEmptyTextNodes(forward, parent.dom, pos).isNone());
  11237. const isAtStartOfBlock = curry(isAtBlockBoundary, false);
  11238. const isAtEndOfBlock = curry(isAtBlockBoundary, true);
  11239. const isBeforeBlock = curry(isAtBeforeAfterBlockBoundary, false);
  11240. const isAfterBlock = curry(isAtBeforeAfterBlockBoundary, true);
  11241. const isBr$1 = pos => getElementFromPosition(pos).exists(isBr$5);
  11242. const findBr = (forward, root, pos) => {
  11243. const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
  11244. const scope = head(parentBlocks).getOr(root);
  11245. return fromPosition(forward, scope.dom, pos).filter(isBr$1);
  11246. };
  11247. const isBeforeBr$1 = (root, pos) => getElementFromPosition(pos).exists(isBr$5) || findBr(true, root, pos).isSome();
  11248. const isAfterBr = (root, pos) => getElementFromPrevPosition(pos).exists(isBr$5) || findBr(false, root, pos).isSome();
  11249. const findPreviousBr = curry(findBr, false);
  11250. const findNextBr = curry(findBr, true);
  11251. const isInMiddleOfText = pos => CaretPosition.isTextPosition(pos) && !pos.isAtStart() && !pos.isAtEnd();
  11252. const getClosestBlock = (root, pos) => {
  11253. const parentBlocks = filter$5(parentsAndSelf(SugarElement.fromDom(pos.container()), root), isBlock$2);
  11254. return head(parentBlocks).getOr(root);
  11255. };
  11256. const hasSpaceBefore = (root, pos) => {
  11257. if (isInMiddleOfText(pos)) {
  11258. return isAfterSpace(pos);
  11259. } else {
  11260. return isAfterSpace(pos) || prevPosition(getClosestBlock(root, pos).dom, pos).exists(isAfterSpace);
  11261. }
  11262. };
  11263. const hasSpaceAfter = (root, pos) => {
  11264. if (isInMiddleOfText(pos)) {
  11265. return isBeforeSpace(pos);
  11266. } else {
  11267. return isBeforeSpace(pos) || nextPosition(getClosestBlock(root, pos).dom, pos).exists(isBeforeSpace);
  11268. }
  11269. };
  11270. const isPreValue = value => contains$2([
  11271. 'pre',
  11272. 'pre-wrap'
  11273. ], value);
  11274. const isInPre = pos => getElementFromPosition(pos).bind(elm => closest$4(elm, isElement$7)).exists(elm => isPreValue(get$7(elm, 'white-space')));
  11275. const isAtBeginningOfBody = (root, pos) => prevPosition(root.dom, pos).isNone();
  11276. const isAtEndOfBody = (root, pos) => nextPosition(root.dom, pos).isNone();
  11277. const isAtLineBoundary = (root, pos) => isAtBeginningOfBody(root, pos) || isAtEndOfBody(root, pos) || isAtStartOfBlock(root, pos) || isAtEndOfBlock(root, pos) || isAfterBr(root, pos) || isBeforeBr$1(root, pos);
  11278. const isCefBlock = node => isNonNullable(node) && isContentEditableFalse$a(node) && isBlockLike(node);
  11279. const isSiblingCefBlock = (root, direction) => container => {
  11280. return isCefBlock(new DomTreeWalker(container, root)[direction]());
  11281. };
  11282. const isBeforeCefBlock = (root, pos) => {
  11283. const nextPos = nextPosition(root.dom, pos).getOr(pos);
  11284. const isNextCefBlock = isSiblingCefBlock(root.dom, 'next');
  11285. return pos.isAtEnd() && (isNextCefBlock(pos.container()) || isNextCefBlock(nextPos.container()));
  11286. };
  11287. const isAfterCefBlock = (root, pos) => {
  11288. const prevPos = prevPosition(root.dom, pos).getOr(pos);
  11289. const isPrevCefBlock = isSiblingCefBlock(root.dom, 'prev');
  11290. return pos.isAtStart() && (isPrevCefBlock(pos.container()) || isPrevCefBlock(prevPos.container()));
  11291. };
  11292. const needsToHaveNbsp = (root, pos) => {
  11293. if (isInPre(pos)) {
  11294. return false;
  11295. } else {
  11296. return isAtLineBoundary(root, pos) || hasSpaceBefore(root, pos) || hasSpaceAfter(root, pos);
  11297. }
  11298. };
  11299. const needsToBeNbspLeft = (root, pos) => {
  11300. if (isInPre(pos)) {
  11301. return false;
  11302. } else {
  11303. return isAtStartOfBlock(root, pos) || isBeforeBlock(root, pos) || isAfterBr(root, pos) || hasSpaceBefore(root, pos) || isAfterCefBlock(root, pos);
  11304. }
  11305. };
  11306. const leanRight = pos => {
  11307. const container = pos.container();
  11308. const offset = pos.offset();
  11309. if (isText$a(container) && offset < container.data.length) {
  11310. return CaretPosition(container, offset + 1);
  11311. } else {
  11312. return pos;
  11313. }
  11314. };
  11315. const needsToBeNbspRight = (root, pos) => {
  11316. if (isInPre(pos)) {
  11317. return false;
  11318. } else {
  11319. return isAtEndOfBlock(root, pos) || isAfterBlock(root, pos) || isBeforeBr$1(root, pos) || hasSpaceAfter(root, pos) || isBeforeCefBlock(root, pos);
  11320. }
  11321. };
  11322. const needsToBeNbsp = (root, pos) => needsToBeNbspLeft(root, pos) || needsToBeNbspRight(root, leanRight(pos));
  11323. const isNbspAt = (text, offset) => isNbsp(text.charAt(offset));
  11324. const isWhiteSpaceAt = (text, offset) => isWhiteSpace(text.charAt(offset));
  11325. const hasNbsp = pos => {
  11326. const container = pos.container();
  11327. return isText$a(container) && contains$1(container.data, nbsp);
  11328. };
  11329. const normalizeNbspMiddle = text => {
  11330. const chars = text.split('');
  11331. return map$3(chars, (chr, i) => {
  11332. if (isNbsp(chr) && i > 0 && i < chars.length - 1 && isContent(chars[i - 1]) && isContent(chars[i + 1])) {
  11333. return ' ';
  11334. } else {
  11335. return chr;
  11336. }
  11337. }).join('');
  11338. };
  11339. const normalizeNbspAtStart = (root, node, makeNbsp) => {
  11340. const text = node.data;
  11341. const firstPos = CaretPosition(node, 0);
  11342. if (!makeNbsp && isNbspAt(text, 0) && !needsToBeNbsp(root, firstPos)) {
  11343. node.data = ' ' + text.slice(1);
  11344. return true;
  11345. } else if (makeNbsp && isWhiteSpaceAt(text, 0) && needsToBeNbspLeft(root, firstPos)) {
  11346. node.data = nbsp + text.slice(1);
  11347. return true;
  11348. } else {
  11349. return false;
  11350. }
  11351. };
  11352. const normalizeNbspInMiddleOfTextNode = node => {
  11353. const text = node.data;
  11354. const newText = normalizeNbspMiddle(text);
  11355. if (newText !== text) {
  11356. node.data = newText;
  11357. return true;
  11358. } else {
  11359. return false;
  11360. }
  11361. };
  11362. const normalizeNbspAtEnd = (root, node, makeNbsp) => {
  11363. const text = node.data;
  11364. const lastPos = CaretPosition(node, text.length - 1);
  11365. if (!makeNbsp && isNbspAt(text, text.length - 1) && !needsToBeNbsp(root, lastPos)) {
  11366. node.data = text.slice(0, -1) + ' ';
  11367. return true;
  11368. } else if (makeNbsp && isWhiteSpaceAt(text, text.length - 1) && needsToBeNbspRight(root, lastPos)) {
  11369. node.data = text.slice(0, -1) + nbsp;
  11370. return true;
  11371. } else {
  11372. return false;
  11373. }
  11374. };
  11375. const normalizeNbsps = (root, pos) => {
  11376. const container = pos.container();
  11377. if (!isText$a(container)) {
  11378. return Optional.none();
  11379. }
  11380. if (hasNbsp(pos)) {
  11381. const normalized = normalizeNbspAtStart(root, container, false) || normalizeNbspInMiddleOfTextNode(container) || normalizeNbspAtEnd(root, container, false);
  11382. return someIf(normalized, pos);
  11383. } else if (needsToBeNbsp(root, pos)) {
  11384. const normalized = normalizeNbspAtStart(root, container, true) || normalizeNbspAtEnd(root, container, true);
  11385. return someIf(normalized, pos);
  11386. } else {
  11387. return Optional.none();
  11388. }
  11389. };
  11390. const normalizeNbspsInEditor = editor => {
  11391. const root = SugarElement.fromDom(editor.getBody());
  11392. if (editor.selection.isCollapsed()) {
  11393. normalizeNbsps(root, CaretPosition.fromRangeStart(editor.selection.getRng())).each(pos => {
  11394. editor.selection.setRng(pos.toRange());
  11395. });
  11396. }
  11397. };
  11398. const normalize$1 = (node, offset, count) => {
  11399. if (count === 0) {
  11400. return;
  11401. }
  11402. const elm = SugarElement.fromDom(node);
  11403. const root = ancestor$3(elm, isBlock$2).getOr(elm);
  11404. const whitespace = node.data.slice(offset, offset + count);
  11405. const isEndOfContent = offset + count >= node.data.length && needsToBeNbspRight(root, CaretPosition(node, node.data.length));
  11406. const isStartOfContent = offset === 0 && needsToBeNbspLeft(root, CaretPosition(node, 0));
  11407. node.replaceData(offset, count, normalize$4(whitespace, 4, isStartOfContent, isEndOfContent));
  11408. };
  11409. const normalizeWhitespaceAfter = (node, offset) => {
  11410. const content = node.data.slice(offset);
  11411. const whitespaceCount = content.length - lTrim(content).length;
  11412. normalize$1(node, offset, whitespaceCount);
  11413. };
  11414. const normalizeWhitespaceBefore = (node, offset) => {
  11415. const content = node.data.slice(0, offset);
  11416. const whitespaceCount = content.length - rTrim(content).length;
  11417. normalize$1(node, offset - whitespaceCount, whitespaceCount);
  11418. };
  11419. const mergeTextNodes = (prevNode, nextNode, normalizeWhitespace, mergeToPrev = true) => {
  11420. const whitespaceOffset = rTrim(prevNode.data).length;
  11421. const newNode = mergeToPrev ? prevNode : nextNode;
  11422. const removeNode = mergeToPrev ? nextNode : prevNode;
  11423. if (mergeToPrev) {
  11424. newNode.appendData(removeNode.data);
  11425. } else {
  11426. newNode.insertData(0, removeNode.data);
  11427. }
  11428. remove$6(SugarElement.fromDom(removeNode));
  11429. if (normalizeWhitespace) {
  11430. normalizeWhitespaceAfter(newNode, whitespaceOffset);
  11431. }
  11432. return newNode;
  11433. };
  11434. const needsReposition = (pos, elm) => {
  11435. const container = pos.container();
  11436. const offset = pos.offset();
  11437. return !CaretPosition.isTextPosition(pos) && container === elm.parentNode && offset > CaretPosition.before(elm).offset();
  11438. };
  11439. const reposition = (elm, pos) => needsReposition(pos, elm) ? CaretPosition(pos.container(), pos.offset() - 1) : pos;
  11440. const beforeOrStartOf = node => isText$a(node) ? CaretPosition(node, 0) : CaretPosition.before(node);
  11441. const afterOrEndOf = node => isText$a(node) ? CaretPosition(node, node.data.length) : CaretPosition.after(node);
  11442. const getPreviousSiblingCaretPosition = elm => {
  11443. if (isCaretCandidate$3(elm.previousSibling)) {
  11444. return Optional.some(afterOrEndOf(elm.previousSibling));
  11445. } else {
  11446. return elm.previousSibling ? lastPositionIn(elm.previousSibling) : Optional.none();
  11447. }
  11448. };
  11449. const getNextSiblingCaretPosition = elm => {
  11450. if (isCaretCandidate$3(elm.nextSibling)) {
  11451. return Optional.some(beforeOrStartOf(elm.nextSibling));
  11452. } else {
  11453. return elm.nextSibling ? firstPositionIn(elm.nextSibling) : Optional.none();
  11454. }
  11455. };
  11456. const findCaretPositionBackwardsFromElm = (rootElement, elm) => {
  11457. return Optional.from(elm.previousSibling ? elm.previousSibling : elm.parentNode).bind(node => prevPosition(rootElement, CaretPosition.before(node))).orThunk(() => nextPosition(rootElement, CaretPosition.after(elm)));
  11458. };
  11459. const findCaretPositionForwardsFromElm = (rootElement, elm) => nextPosition(rootElement, CaretPosition.after(elm)).orThunk(() => prevPosition(rootElement, CaretPosition.before(elm)));
  11460. const findCaretPositionBackwards = (rootElement, elm) => getPreviousSiblingCaretPosition(elm).orThunk(() => getNextSiblingCaretPosition(elm)).orThunk(() => findCaretPositionBackwardsFromElm(rootElement, elm));
  11461. const findCaretPositionForward = (rootElement, elm) => getNextSiblingCaretPosition(elm).orThunk(() => getPreviousSiblingCaretPosition(elm)).orThunk(() => findCaretPositionForwardsFromElm(rootElement, elm));
  11462. const findCaretPosition = (forward, rootElement, elm) => forward ? findCaretPositionForward(rootElement, elm) : findCaretPositionBackwards(rootElement, elm);
  11463. const findCaretPosOutsideElmAfterDelete = (forward, rootElement, elm) => findCaretPosition(forward, rootElement, elm).map(curry(reposition, elm));
  11464. const setSelection$1 = (editor, forward, pos) => {
  11465. pos.fold(() => {
  11466. editor.focus();
  11467. }, pos => {
  11468. editor.selection.setRng(pos.toRange(), forward);
  11469. });
  11470. };
  11471. const eqRawNode = rawNode => elm => elm.dom === rawNode;
  11472. const isBlock = (editor, elm) => elm && has$2(editor.schema.getBlockElements(), name(elm));
  11473. const paddEmptyBlock = elm => {
  11474. if (isEmpty$2(elm)) {
  11475. const br = SugarElement.fromHtml('<br data-mce-bogus="1">');
  11476. empty(elm);
  11477. append$1(elm, br);
  11478. return Optional.some(CaretPosition.before(br.dom));
  11479. } else {
  11480. return Optional.none();
  11481. }
  11482. };
  11483. const deleteNormalized = (elm, afterDeletePosOpt, normalizeWhitespace) => {
  11484. const prevTextOpt = prevSibling(elm).filter(isText$b);
  11485. const nextTextOpt = nextSibling(elm).filter(isText$b);
  11486. remove$6(elm);
  11487. return lift3(prevTextOpt, nextTextOpt, afterDeletePosOpt, (prev, next, pos) => {
  11488. const prevNode = prev.dom, nextNode = next.dom;
  11489. const offset = prevNode.data.length;
  11490. mergeTextNodes(prevNode, nextNode, normalizeWhitespace);
  11491. return pos.container() === nextNode ? CaretPosition(prevNode, offset) : pos;
  11492. }).orThunk(() => {
  11493. if (normalizeWhitespace) {
  11494. prevTextOpt.each(elm => normalizeWhitespaceBefore(elm.dom, elm.dom.length));
  11495. nextTextOpt.each(elm => normalizeWhitespaceAfter(elm.dom, 0));
  11496. }
  11497. return afterDeletePosOpt;
  11498. });
  11499. };
  11500. const isInlineElement = (editor, element) => has$2(editor.schema.getTextInlineElements(), name(element));
  11501. const deleteElement$2 = (editor, forward, elm, moveCaret = true) => {
  11502. const afterDeletePos = findCaretPosOutsideElmAfterDelete(forward, editor.getBody(), elm.dom);
  11503. const parentBlock = ancestor$3(elm, curry(isBlock, editor), eqRawNode(editor.getBody()));
  11504. const normalizedAfterDeletePos = deleteNormalized(elm, afterDeletePos, isInlineElement(editor, elm));
  11505. if (editor.dom.isEmpty(editor.getBody())) {
  11506. editor.setContent('');
  11507. editor.selection.setCursorLocation();
  11508. } else {
  11509. parentBlock.bind(paddEmptyBlock).fold(() => {
  11510. if (moveCaret) {
  11511. setSelection$1(editor, forward, normalizedAfterDeletePos);
  11512. }
  11513. }, paddPos => {
  11514. if (moveCaret) {
  11515. setSelection$1(editor, forward, Optional.some(paddPos));
  11516. }
  11517. });
  11518. }
  11519. };
  11520. const strongRtl = /[\u0591-\u07FF\uFB1D-\uFDFF\uFE70-\uFEFC]/;
  11521. const hasStrongRtl = text => strongRtl.test(text);
  11522. const isInlineTarget = (editor, elm) => is$1(SugarElement.fromDom(elm), getInlineBoundarySelector(editor)) && !isTransparentBlock(editor.schema, elm);
  11523. const isRtl = element => {
  11524. var _a;
  11525. return DOMUtils.DOM.getStyle(element, 'direction', true) === 'rtl' || hasStrongRtl((_a = element.textContent) !== null && _a !== void 0 ? _a : '');
  11526. };
  11527. const findInlineParents = (isInlineTarget, rootNode, pos) => filter$5(DOMUtils.DOM.getParents(pos.container(), '*', rootNode), isInlineTarget);
  11528. const findRootInline = (isInlineTarget, rootNode, pos) => {
  11529. const parents = findInlineParents(isInlineTarget, rootNode, pos);
  11530. return Optional.from(parents[parents.length - 1]);
  11531. };
  11532. const hasSameParentBlock = (rootNode, node1, node2) => {
  11533. const block1 = getParentBlock$3(node1, rootNode);
  11534. const block2 = getParentBlock$3(node2, rootNode);
  11535. return isNonNullable(block1) && block1 === block2;
  11536. };
  11537. const isAtZwsp = pos => isBeforeInline(pos) || isAfterInline(pos);
  11538. const normalizePosition = (forward, pos) => {
  11539. const container = pos.container(), offset = pos.offset();
  11540. if (forward) {
  11541. if (isCaretContainerInline(container)) {
  11542. if (isText$a(container.nextSibling)) {
  11543. return CaretPosition(container.nextSibling, 0);
  11544. } else {
  11545. return CaretPosition.after(container);
  11546. }
  11547. } else {
  11548. return isBeforeInline(pos) ? CaretPosition(container, offset + 1) : pos;
  11549. }
  11550. } else {
  11551. if (isCaretContainerInline(container)) {
  11552. if (isText$a(container.previousSibling)) {
  11553. return CaretPosition(container.previousSibling, container.previousSibling.data.length);
  11554. } else {
  11555. return CaretPosition.before(container);
  11556. }
  11557. } else {
  11558. return isAfterInline(pos) ? CaretPosition(container, offset - 1) : pos;
  11559. }
  11560. }
  11561. };
  11562. const normalizeForwards = curry(normalizePosition, true);
  11563. const normalizeBackwards = curry(normalizePosition, false);
  11564. const execCommandIgnoreInputEvents = (editor, command) => {
  11565. const inputBlocker = e => e.stopImmediatePropagation();
  11566. editor.on('beforeinput input', inputBlocker, true);
  11567. editor.getDoc().execCommand(command);
  11568. editor.off('beforeinput input', inputBlocker);
  11569. };
  11570. const execEditorDeleteCommand = editor => {
  11571. editor.execCommand('delete');
  11572. };
  11573. const execNativeDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'Delete');
  11574. const execNativeForwardDeleteCommand = editor => execCommandIgnoreInputEvents(editor, 'ForwardDelete');
  11575. const isBeforeRoot = rootNode => elm => is$2(parent(elm), rootNode, eq);
  11576. const isTextBlockOrListItem = element => isTextBlock$2(element) || isListItem$1(element);
  11577. const getParentBlock$2 = (rootNode, elm) => {
  11578. if (contains(rootNode, elm)) {
  11579. return closest$4(elm, isTextBlockOrListItem, isBeforeRoot(rootNode));
  11580. } else {
  11581. return Optional.none();
  11582. }
  11583. };
  11584. const paddEmptyBody = (editor, moveSelection = true) => {
  11585. if (editor.dom.isEmpty(editor.getBody())) {
  11586. editor.setContent('', { no_selection: !moveSelection });
  11587. }
  11588. };
  11589. const willDeleteLastPositionInElement = (forward, fromPos, elm) => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
  11590. const normalizedFirstPos = normalizePosition(true, firstPos);
  11591. const normalizedLastPos = normalizePosition(false, lastPos);
  11592. const normalizedFromPos = normalizePosition(false, fromPos);
  11593. if (forward) {
  11594. return nextPosition(elm, normalizedFromPos).exists(nextPos => nextPos.isEqual(normalizedLastPos) && fromPos.isEqual(normalizedFirstPos));
  11595. } else {
  11596. return prevPosition(elm, normalizedFromPos).exists(prevPos => prevPos.isEqual(normalizedFirstPos) && fromPos.isEqual(normalizedLastPos));
  11597. }
  11598. }).getOr(true);
  11599. const freefallRtl = root => {
  11600. const child = isComment$1(root) ? prevSibling(root) : lastChild(root);
  11601. return child.bind(freefallRtl).orThunk(() => Optional.some(root));
  11602. };
  11603. const deleteRangeContents = (editor, rng, root, moveSelection = true) => {
  11604. var _a;
  11605. rng.deleteContents();
  11606. const lastNode = freefallRtl(root).getOr(root);
  11607. const lastBlock = SugarElement.fromDom((_a = editor.dom.getParent(lastNode.dom, editor.dom.isBlock)) !== null && _a !== void 0 ? _a : root.dom);
  11608. if (lastBlock.dom === editor.getBody()) {
  11609. paddEmptyBody(editor, moveSelection);
  11610. } else if (isEmpty$2(lastBlock)) {
  11611. fillWithPaddingBr(lastBlock);
  11612. if (moveSelection) {
  11613. editor.selection.setCursorLocation(lastBlock.dom, 0);
  11614. }
  11615. }
  11616. if (!eq(root, lastBlock)) {
  11617. const additionalCleanupNodes = is$2(parent(lastBlock), root) ? [] : siblings(lastBlock);
  11618. each$e(additionalCleanupNodes.concat(children$1(root)), node => {
  11619. if (!eq(node, lastBlock) && !contains(node, lastBlock) && isEmpty$2(node)) {
  11620. remove$6(node);
  11621. }
  11622. });
  11623. }
  11624. };
  11625. const isRootFromElement = root => cur => eq(root, cur);
  11626. const getTableCells = table => descendants(table, 'td,th');
  11627. const getTableDetailsFromRange = (rng, isRoot) => {
  11628. const getTable = node => getClosestTable(SugarElement.fromDom(node), isRoot);
  11629. const startTable = getTable(rng.startContainer);
  11630. const endTable = getTable(rng.endContainer);
  11631. const isStartInTable = startTable.isSome();
  11632. const isEndInTable = endTable.isSome();
  11633. const isSameTable = lift2(startTable, endTable, eq).getOr(false);
  11634. const isMultiTable = !isSameTable && isStartInTable && isEndInTable;
  11635. return {
  11636. startTable,
  11637. endTable,
  11638. isStartInTable,
  11639. isEndInTable,
  11640. isSameTable,
  11641. isMultiTable
  11642. };
  11643. };
  11644. const tableCellRng = (start, end) => ({
  11645. start,
  11646. end
  11647. });
  11648. const tableSelection = (rng, table, cells) => ({
  11649. rng,
  11650. table,
  11651. cells
  11652. });
  11653. const deleteAction = Adt.generate([
  11654. {
  11655. singleCellTable: [
  11656. 'rng',
  11657. 'cell'
  11658. ]
  11659. },
  11660. { fullTable: ['table'] },
  11661. {
  11662. partialTable: [
  11663. 'cells',
  11664. 'outsideDetails'
  11665. ]
  11666. },
  11667. {
  11668. multiTable: [
  11669. 'startTableCells',
  11670. 'endTableCells',
  11671. 'betweenRng'
  11672. ]
  11673. }
  11674. ]);
  11675. const getClosestCell$1 = (container, isRoot) => closest$3(SugarElement.fromDom(container), 'td,th', isRoot);
  11676. const isExpandedCellRng = cellRng => !eq(cellRng.start, cellRng.end);
  11677. const getTableFromCellRng = (cellRng, isRoot) => getClosestTable(cellRng.start, isRoot).bind(startParentTable => getClosestTable(cellRng.end, isRoot).bind(endParentTable => someIf(eq(startParentTable, endParentTable), startParentTable)));
  11678. const isSingleCellTable = (cellRng, isRoot) => !isExpandedCellRng(cellRng) && getTableFromCellRng(cellRng, isRoot).exists(table => {
  11679. const rows = table.dom.rows;
  11680. return rows.length === 1 && rows[0].cells.length === 1;
  11681. });
  11682. const getCellRng = (rng, isRoot) => {
  11683. const startCell = getClosestCell$1(rng.startContainer, isRoot);
  11684. const endCell = getClosestCell$1(rng.endContainer, isRoot);
  11685. return lift2(startCell, endCell, tableCellRng);
  11686. };
  11687. const getCellRangeFromStartTable = isRoot => startCell => getClosestTable(startCell, isRoot).bind(table => last$3(getTableCells(table)).map(endCell => tableCellRng(startCell, endCell)));
  11688. const getCellRangeFromEndTable = isRoot => endCell => getClosestTable(endCell, isRoot).bind(table => head(getTableCells(table)).map(startCell => tableCellRng(startCell, endCell)));
  11689. const getTableSelectionFromCellRng = isRoot => cellRng => getTableFromCellRng(cellRng, isRoot).map(table => tableSelection(cellRng, table, getTableCells(table)));
  11690. const getTableSelections = (cellRng, selectionDetails, rng, isRoot) => {
  11691. if (rng.collapsed || !cellRng.forall(isExpandedCellRng)) {
  11692. return Optional.none();
  11693. } else if (selectionDetails.isSameTable) {
  11694. const sameTableSelection = cellRng.bind(getTableSelectionFromCellRng(isRoot));
  11695. return Optional.some({
  11696. start: sameTableSelection,
  11697. end: sameTableSelection
  11698. });
  11699. } else {
  11700. const startCell = getClosestCell$1(rng.startContainer, isRoot);
  11701. const endCell = getClosestCell$1(rng.endContainer, isRoot);
  11702. const startTableSelection = startCell.bind(getCellRangeFromStartTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
  11703. const endTableSelection = endCell.bind(getCellRangeFromEndTable(isRoot)).bind(getTableSelectionFromCellRng(isRoot));
  11704. return Optional.some({
  11705. start: startTableSelection,
  11706. end: endTableSelection
  11707. });
  11708. }
  11709. };
  11710. const getCellIndex = (cells, cell) => findIndex$2(cells, x => eq(x, cell));
  11711. const getSelectedCells = tableSelection => lift2(getCellIndex(tableSelection.cells, tableSelection.rng.start), getCellIndex(tableSelection.cells, tableSelection.rng.end), (startIndex, endIndex) => tableSelection.cells.slice(startIndex, endIndex + 1));
  11712. const isSingleCellTableContentSelected = (optCellRng, rng, isRoot) => optCellRng.exists(cellRng => isSingleCellTable(cellRng, isRoot) && hasAllContentsSelected(cellRng.start, rng));
  11713. const unselectCells = (rng, selectionDetails) => {
  11714. const {startTable, endTable} = selectionDetails;
  11715. const otherContentRng = rng.cloneRange();
  11716. startTable.each(table => otherContentRng.setStartAfter(table.dom));
  11717. endTable.each(table => otherContentRng.setEndBefore(table.dom));
  11718. return otherContentRng;
  11719. };
  11720. const handleSingleTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => start.or(end)).bind(tableSelection => {
  11721. const {isSameTable} = selectionDetails;
  11722. const selectedCells = getSelectedCells(tableSelection).getOr([]);
  11723. if (isSameTable && tableSelection.cells.length === selectedCells.length) {
  11724. return Optional.some(deleteAction.fullTable(tableSelection.table));
  11725. } else if (selectedCells.length > 0) {
  11726. if (isSameTable) {
  11727. return Optional.some(deleteAction.partialTable(selectedCells, Optional.none()));
  11728. } else {
  11729. const otherContentRng = unselectCells(rng, selectionDetails);
  11730. return Optional.some(deleteAction.partialTable(selectedCells, Optional.some({
  11731. ...selectionDetails,
  11732. rng: otherContentRng
  11733. })));
  11734. }
  11735. } else {
  11736. return Optional.none();
  11737. }
  11738. });
  11739. const handleMultiTable = (cellRng, selectionDetails, rng, isRoot) => getTableSelections(cellRng, selectionDetails, rng, isRoot).bind(({start, end}) => {
  11740. const startTableSelectedCells = start.bind(getSelectedCells).getOr([]);
  11741. const endTableSelectedCells = end.bind(getSelectedCells).getOr([]);
  11742. if (startTableSelectedCells.length > 0 && endTableSelectedCells.length > 0) {
  11743. const otherContentRng = unselectCells(rng, selectionDetails);
  11744. return Optional.some(deleteAction.multiTable(startTableSelectedCells, endTableSelectedCells, otherContentRng));
  11745. } else {
  11746. return Optional.none();
  11747. }
  11748. });
  11749. const getActionFromRange = (root, rng) => {
  11750. const isRoot = isRootFromElement(root);
  11751. const optCellRng = getCellRng(rng, isRoot);
  11752. const selectionDetails = getTableDetailsFromRange(rng, isRoot);
  11753. if (isSingleCellTableContentSelected(optCellRng, rng, isRoot)) {
  11754. return optCellRng.map(cellRng => deleteAction.singleCellTable(rng, cellRng.start));
  11755. } else if (selectionDetails.isMultiTable) {
  11756. return handleMultiTable(optCellRng, selectionDetails, rng, isRoot);
  11757. } else {
  11758. return handleSingleTable(optCellRng, selectionDetails, rng, isRoot);
  11759. }
  11760. };
  11761. const cleanCells = cells => each$e(cells, cell => {
  11762. remove$b(cell, 'contenteditable');
  11763. fillWithPaddingBr(cell);
  11764. });
  11765. const getOutsideBlock = (editor, container) => Optional.from(editor.dom.getParent(container, editor.dom.isBlock)).map(SugarElement.fromDom);
  11766. const handleEmptyBlock = (editor, startInTable, emptyBlock) => {
  11767. emptyBlock.each(block => {
  11768. if (startInTable) {
  11769. remove$6(block);
  11770. } else {
  11771. fillWithPaddingBr(block);
  11772. editor.selection.setCursorLocation(block.dom, 0);
  11773. }
  11774. });
  11775. };
  11776. const deleteContentInsideCell = (editor, cell, rng, isFirstCellInSelection) => {
  11777. const insideTableRng = rng.cloneRange();
  11778. if (isFirstCellInSelection) {
  11779. insideTableRng.setStart(rng.startContainer, rng.startOffset);
  11780. insideTableRng.setEndAfter(cell.dom.lastChild);
  11781. } else {
  11782. insideTableRng.setStartBefore(cell.dom.firstChild);
  11783. insideTableRng.setEnd(rng.endContainer, rng.endOffset);
  11784. }
  11785. deleteCellContents(editor, insideTableRng, cell, false).each(action => action());
  11786. };
  11787. const collapseAndRestoreCellSelection = editor => {
  11788. const selectedCells = getCellsFromEditor(editor);
  11789. const selectedNode = SugarElement.fromDom(editor.selection.getNode());
  11790. if (isTableCell$3(selectedNode.dom) && isEmpty$2(selectedNode)) {
  11791. editor.selection.setCursorLocation(selectedNode.dom, 0);
  11792. } else {
  11793. editor.selection.collapse(true);
  11794. }
  11795. if (selectedCells.length > 1 && exists(selectedCells, cell => eq(cell, selectedNode))) {
  11796. set$2(selectedNode, 'data-mce-selected', '1');
  11797. }
  11798. };
  11799. const emptySingleTableCells = (editor, cells, outsideDetails) => Optional.some(() => {
  11800. const editorRng = editor.selection.getRng();
  11801. const cellsToClean = outsideDetails.bind(({rng, isStartInTable}) => {
  11802. const outsideBlock = getOutsideBlock(editor, isStartInTable ? rng.endContainer : rng.startContainer);
  11803. rng.deleteContents();
  11804. handleEmptyBlock(editor, isStartInTable, outsideBlock.filter(isEmpty$2));
  11805. const endPointCell = isStartInTable ? cells[0] : cells[cells.length - 1];
  11806. deleteContentInsideCell(editor, endPointCell, editorRng, isStartInTable);
  11807. if (!isEmpty$2(endPointCell)) {
  11808. return Optional.some(isStartInTable ? cells.slice(1) : cells.slice(0, -1));
  11809. } else {
  11810. return Optional.none();
  11811. }
  11812. }).getOr(cells);
  11813. cleanCells(cellsToClean);
  11814. collapseAndRestoreCellSelection(editor);
  11815. });
  11816. const emptyMultiTableCells = (editor, startTableCells, endTableCells, betweenRng) => Optional.some(() => {
  11817. const rng = editor.selection.getRng();
  11818. const startCell = startTableCells[0];
  11819. const endCell = endTableCells[endTableCells.length - 1];
  11820. deleteContentInsideCell(editor, startCell, rng, true);
  11821. deleteContentInsideCell(editor, endCell, rng, false);
  11822. const startTableCellsToClean = isEmpty$2(startCell) ? startTableCells : startTableCells.slice(1);
  11823. const endTableCellsToClean = isEmpty$2(endCell) ? endTableCells : endTableCells.slice(0, -1);
  11824. cleanCells(startTableCellsToClean.concat(endTableCellsToClean));
  11825. betweenRng.deleteContents();
  11826. collapseAndRestoreCellSelection(editor);
  11827. });
  11828. const deleteCellContents = (editor, rng, cell, moveSelection = true) => Optional.some(() => {
  11829. deleteRangeContents(editor, rng, cell, moveSelection);
  11830. });
  11831. const deleteTableElement = (editor, table) => Optional.some(() => deleteElement$2(editor, false, table));
  11832. const deleteCellRange = (editor, rootElm, rng) => getActionFromRange(rootElm, rng).bind(action => action.fold(curry(deleteCellContents, editor), curry(deleteTableElement, editor), curry(emptySingleTableCells, editor), curry(emptyMultiTableCells, editor)));
  11833. const deleteCaptionRange = (editor, caption) => emptyElement(editor, caption);
  11834. const deleteTableRange = (editor, rootElm, rng, startElm) => getParentCaption(rootElm, startElm).fold(() => deleteCellRange(editor, rootElm, rng), caption => deleteCaptionRange(editor, caption));
  11835. const deleteRange$2 = (editor, startElm, selectedCells) => {
  11836. const rootNode = SugarElement.fromDom(editor.getBody());
  11837. const rng = editor.selection.getRng();
  11838. return selectedCells.length !== 0 ? emptySingleTableCells(editor, selectedCells, Optional.none()) : deleteTableRange(editor, rootNode, rng, startElm);
  11839. };
  11840. const getParentCell = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTableCell$2);
  11841. const getParentCaption = (rootElm, elm) => find$2(parentsAndSelf(elm, rootElm), isTag('caption'));
  11842. const deleteBetweenCells = (editor, rootElm, forward, fromCell, from) => navigate(forward, editor.getBody(), from).bind(to => getParentCell(rootElm, SugarElement.fromDom(to.getNode())).bind(toCell => eq(toCell, fromCell) ? Optional.none() : Optional.some(noop)));
  11843. const emptyElement = (editor, elm) => Optional.some(() => {
  11844. fillWithPaddingBr(elm);
  11845. editor.selection.setCursorLocation(elm.dom, 0);
  11846. });
  11847. const isDeleteOfLastCharPos = (fromCaption, forward, from, to) => firstPositionIn(fromCaption.dom).bind(first => lastPositionIn(fromCaption.dom).map(last => forward ? from.isEqual(first) && to.isEqual(last) : from.isEqual(last) && to.isEqual(first))).getOr(true);
  11848. const emptyCaretCaption = (editor, elm) => emptyElement(editor, elm);
  11849. const validateCaretCaption = (rootElm, fromCaption, to) => getParentCaption(rootElm, SugarElement.fromDom(to.getNode())).fold(() => Optional.some(noop), toCaption => someIf(!eq(toCaption, fromCaption), noop));
  11850. const deleteCaretInsideCaption = (editor, rootElm, forward, fromCaption, from) => navigate(forward, editor.getBody(), from).fold(() => Optional.some(noop), to => isDeleteOfLastCharPos(fromCaption, forward, from, to) ? emptyCaretCaption(editor, fromCaption) : validateCaretCaption(rootElm, fromCaption, to));
  11851. const deleteCaretCells = (editor, forward, rootElm, startElm) => {
  11852. const from = CaretPosition.fromRangeStart(editor.selection.getRng());
  11853. return getParentCell(rootElm, startElm).bind(fromCell => isEmpty$2(fromCell) ? emptyElement(editor, fromCell) : deleteBetweenCells(editor, rootElm, forward, fromCell, from));
  11854. };
  11855. const deleteCaretCaption = (editor, forward, rootElm, fromCaption) => {
  11856. const from = CaretPosition.fromRangeStart(editor.selection.getRng());
  11857. return isEmpty$2(fromCaption) ? emptyElement(editor, fromCaption) : deleteCaretInsideCaption(editor, rootElm, forward, fromCaption, from);
  11858. };
  11859. const isNearTable = (forward, pos) => forward ? isBeforeTable(pos) : isAfterTable(pos);
  11860. const isBeforeOrAfterTable = (editor, forward) => {
  11861. const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
  11862. return isNearTable(forward, fromPos) || fromPosition(forward, editor.getBody(), fromPos).exists(pos => isNearTable(forward, pos));
  11863. };
  11864. const deleteCaret$3 = (editor, forward, startElm) => {
  11865. const rootElm = SugarElement.fromDom(editor.getBody());
  11866. return getParentCaption(rootElm, startElm).fold(() => deleteCaretCells(editor, forward, rootElm, startElm).orThunk(() => someIf(isBeforeOrAfterTable(editor, forward), noop)), fromCaption => deleteCaretCaption(editor, forward, rootElm, fromCaption));
  11867. };
  11868. const backspaceDelete$9 = (editor, forward) => {
  11869. const startElm = SugarElement.fromDom(editor.selection.getStart(true));
  11870. const cells = getCellsFromEditor(editor);
  11871. return editor.selection.isCollapsed() && cells.length === 0 ? deleteCaret$3(editor, forward, startElm) : deleteRange$2(editor, startElm, cells);
  11872. };
  11873. const getContentEditableRoot$1 = (root, node) => {
  11874. let tempNode = node;
  11875. while (tempNode && tempNode !== root) {
  11876. if (isContentEditableTrue$3(tempNode) || isContentEditableFalse$a(tempNode)) {
  11877. return tempNode;
  11878. }
  11879. tempNode = tempNode.parentNode;
  11880. }
  11881. return null;
  11882. };
  11883. const internalAttributesPrefixes = [
  11884. 'data-ephox-',
  11885. 'data-mce-',
  11886. 'data-alloy-',
  11887. 'data-snooker-',
  11888. '_'
  11889. ];
  11890. const each$9 = Tools.each;
  11891. const ElementUtils = editor => {
  11892. const dom = editor.dom;
  11893. const internalAttributes = new Set(editor.serializer.getTempAttrs());
  11894. const compare = (node1, node2) => {
  11895. if (node1.nodeName !== node2.nodeName || node1.nodeType !== node2.nodeType) {
  11896. return false;
  11897. }
  11898. const getAttribs = node => {
  11899. const attribs = {};
  11900. each$9(dom.getAttribs(node), attr => {
  11901. const name = attr.nodeName.toLowerCase();
  11902. if (name !== 'style' && !isAttributeInternal(name)) {
  11903. attribs[name] = dom.getAttrib(node, name);
  11904. }
  11905. });
  11906. return attribs;
  11907. };
  11908. const compareObjects = (obj1, obj2) => {
  11909. for (const name in obj1) {
  11910. if (has$2(obj1, name)) {
  11911. const value = obj2[name];
  11912. if (isUndefined(value)) {
  11913. return false;
  11914. }
  11915. if (obj1[name] !== value) {
  11916. return false;
  11917. }
  11918. delete obj2[name];
  11919. }
  11920. }
  11921. for (const name in obj2) {
  11922. if (has$2(obj2, name)) {
  11923. return false;
  11924. }
  11925. }
  11926. return true;
  11927. };
  11928. if (isElement$6(node1) && isElement$6(node2)) {
  11929. if (!compareObjects(getAttribs(node1), getAttribs(node2))) {
  11930. return false;
  11931. }
  11932. if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style')))) {
  11933. return false;
  11934. }
  11935. }
  11936. return !isBookmarkNode$1(node1) && !isBookmarkNode$1(node2);
  11937. };
  11938. const isAttributeInternal = attributeName => exists(internalAttributesPrefixes, value => startsWith(attributeName, value)) || internalAttributes.has(attributeName);
  11939. return {
  11940. compare,
  11941. isAttributeInternal
  11942. };
  11943. };
  11944. const traverse = (root, fn) => {
  11945. let node = root;
  11946. while (node = node.walk()) {
  11947. fn(node);
  11948. }
  11949. };
  11950. const matchNode$1 = (nodeFilters, attributeFilters, node, matches) => {
  11951. const name = node.name;
  11952. for (let ni = 0, nl = nodeFilters.length; ni < nl; ni++) {
  11953. const filter = nodeFilters[ni];
  11954. if (filter.name === name) {
  11955. const match = matches.nodes[name];
  11956. if (match) {
  11957. match.nodes.push(node);
  11958. } else {
  11959. matches.nodes[name] = {
  11960. filter,
  11961. nodes: [node]
  11962. };
  11963. }
  11964. }
  11965. }
  11966. if (node.attributes) {
  11967. for (let ai = 0, al = attributeFilters.length; ai < al; ai++) {
  11968. const filter = attributeFilters[ai];
  11969. const attrName = filter.name;
  11970. if (attrName in node.attributes.map) {
  11971. const match = matches.attributes[attrName];
  11972. if (match) {
  11973. match.nodes.push(node);
  11974. } else {
  11975. matches.attributes[attrName] = {
  11976. filter,
  11977. nodes: [node]
  11978. };
  11979. }
  11980. }
  11981. }
  11982. }
  11983. };
  11984. const findMatchingNodes = (nodeFilters, attributeFilters, node) => {
  11985. const matches = {
  11986. nodes: {},
  11987. attributes: {}
  11988. };
  11989. if (node.firstChild) {
  11990. traverse(node, childNode => {
  11991. matchNode$1(nodeFilters, attributeFilters, childNode, matches);
  11992. });
  11993. }
  11994. return matches;
  11995. };
  11996. const runFilters = (matches, args) => {
  11997. const run = (matchRecord, filteringAttributes) => {
  11998. each$d(matchRecord, match => {
  11999. const nodes = from(match.nodes);
  12000. each$e(match.filter.callbacks, callback => {
  12001. for (let i = nodes.length - 1; i >= 0; i--) {
  12002. const node = nodes[i];
  12003. const valueMatches = filteringAttributes ? node.attr(match.filter.name) !== undefined : node.name === match.filter.name;
  12004. if (!valueMatches || isNullable(node.parent)) {
  12005. nodes.splice(i, 1);
  12006. }
  12007. }
  12008. if (nodes.length > 0) {
  12009. callback(nodes, match.filter.name, args);
  12010. }
  12011. });
  12012. });
  12013. };
  12014. run(matches.nodes, false);
  12015. run(matches.attributes, true);
  12016. };
  12017. const filter$2 = (nodeFilters, attributeFilters, node, args = {}) => {
  12018. const matches = findMatchingNodes(nodeFilters, attributeFilters, node);
  12019. runFilters(matches, args);
  12020. };
  12021. const paddEmptyNode = (args, isBlock, node) => {
  12022. if (args.insert && isBlock(node)) {
  12023. const astNode = new AstNode('br', 1);
  12024. astNode.attr('data-mce-bogus', '1');
  12025. node.empty().append(astNode);
  12026. } else {
  12027. node.empty().append(new AstNode('#text', 3)).value = nbsp;
  12028. }
  12029. };
  12030. const isPaddedWithNbsp = node => {
  12031. var _a;
  12032. return hasOnlyChild(node, '#text') && ((_a = node === null || node === void 0 ? void 0 : node.firstChild) === null || _a === void 0 ? void 0 : _a.value) === nbsp;
  12033. };
  12034. const hasOnlyChild = (node, name) => {
  12035. const firstChild = node === null || node === void 0 ? void 0 : node.firstChild;
  12036. return isNonNullable(firstChild) && firstChild === node.lastChild && firstChild.name === name;
  12037. };
  12038. const isPadded = (schema, node) => {
  12039. const rule = schema.getElementRule(node.name);
  12040. return (rule === null || rule === void 0 ? void 0 : rule.paddEmpty) === true;
  12041. };
  12042. const isEmpty = (schema, nonEmptyElements, whitespaceElements, node) => node.isEmpty(nonEmptyElements, whitespaceElements, node => isPadded(schema, node));
  12043. const isLineBreakNode = (node, isBlock) => isNonNullable(node) && (isBlock(node) || node.name === 'br');
  12044. const removeOrUnwrapInvalidNode = (node, schema, originalNodeParent = node.parent) => {
  12045. if (schema.getSpecialElements()[node.name]) {
  12046. node.empty().remove();
  12047. } else {
  12048. const children = node.children();
  12049. for (const childNode of children) {
  12050. if (originalNodeParent && !schema.isValidChild(originalNodeParent.name, childNode.name)) {
  12051. removeOrUnwrapInvalidNode(childNode, schema, originalNodeParent);
  12052. }
  12053. }
  12054. node.unwrap();
  12055. }
  12056. };
  12057. const cleanInvalidNodes = (nodes, schema, onCreate = noop) => {
  12058. const textBlockElements = schema.getTextBlockElements();
  12059. const nonEmptyElements = schema.getNonEmptyElements();
  12060. const whitespaceElements = schema.getWhitespaceElements();
  12061. const nonSplittableElements = Tools.makeMap('tr,td,th,tbody,thead,tfoot,table');
  12062. const fixed = new Set();
  12063. for (let ni = 0; ni < nodes.length; ni++) {
  12064. const node = nodes[ni];
  12065. let parent;
  12066. let newParent;
  12067. let tempNode;
  12068. if (!node.parent || fixed.has(node)) {
  12069. continue;
  12070. }
  12071. if (textBlockElements[node.name] && node.parent.name === 'li') {
  12072. let sibling = node.next;
  12073. while (sibling) {
  12074. if (textBlockElements[sibling.name]) {
  12075. sibling.name = 'li';
  12076. fixed.add(sibling);
  12077. node.parent.insert(sibling, node.parent);
  12078. } else {
  12079. break;
  12080. }
  12081. sibling = sibling.next;
  12082. }
  12083. node.unwrap();
  12084. continue;
  12085. }
  12086. const parents = [node];
  12087. for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && !nonSplittableElements[parent.name]; parent = parent.parent) {
  12088. parents.push(parent);
  12089. }
  12090. if (parent && parents.length > 1) {
  12091. if (schema.isValidChild(parent.name, node.name)) {
  12092. parents.reverse();
  12093. newParent = parents[0].clone();
  12094. onCreate(newParent);
  12095. let currentNode = newParent;
  12096. for (let i = 0; i < parents.length - 1; i++) {
  12097. if (schema.isValidChild(currentNode.name, parents[i].name)) {
  12098. tempNode = parents[i].clone();
  12099. onCreate(tempNode);
  12100. currentNode.append(tempNode);
  12101. } else {
  12102. tempNode = currentNode;
  12103. }
  12104. for (let childNode = parents[i].firstChild; childNode && childNode !== parents[i + 1];) {
  12105. const nextNode = childNode.next;
  12106. tempNode.append(childNode);
  12107. childNode = nextNode;
  12108. }
  12109. currentNode = tempNode;
  12110. }
  12111. if (!isEmpty(schema, nonEmptyElements, whitespaceElements, newParent)) {
  12112. parent.insert(newParent, parents[0], true);
  12113. parent.insert(node, newParent);
  12114. } else {
  12115. parent.insert(node, parents[0], true);
  12116. }
  12117. parent = parents[0];
  12118. if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent) || hasOnlyChild(parent, 'br')) {
  12119. parent.empty().remove();
  12120. }
  12121. } else {
  12122. removeOrUnwrapInvalidNode(node, schema);
  12123. }
  12124. } else if (node.parent) {
  12125. if (node.name === 'li') {
  12126. let sibling = node.prev;
  12127. if (sibling && (sibling.name === 'ul' || sibling.name === 'ol')) {
  12128. sibling.append(node);
  12129. continue;
  12130. }
  12131. sibling = node.next;
  12132. if (sibling && (sibling.name === 'ul' || sibling.name === 'ol') && sibling.firstChild) {
  12133. sibling.insert(node, sibling.firstChild, true);
  12134. continue;
  12135. }
  12136. const wrapper = new AstNode('ul', 1);
  12137. onCreate(wrapper);
  12138. node.wrap(wrapper);
  12139. continue;
  12140. }
  12141. if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
  12142. const wrapper = new AstNode('div', 1);
  12143. onCreate(wrapper);
  12144. node.wrap(wrapper);
  12145. } else {
  12146. removeOrUnwrapInvalidNode(node, schema);
  12147. }
  12148. }
  12149. }
  12150. };
  12151. const hasClosest = (node, parentName) => {
  12152. let tempNode = node;
  12153. while (tempNode) {
  12154. if (tempNode.name === parentName) {
  12155. return true;
  12156. }
  12157. tempNode = tempNode.parent;
  12158. }
  12159. return false;
  12160. };
  12161. const isInvalid = (schema, node, parent = node.parent) => {
  12162. if (parent && schema.children[node.name] && !schema.isValidChild(parent.name, node.name)) {
  12163. return true;
  12164. } else if (parent && node.name === 'a' && hasClosest(parent, 'a')) {
  12165. return true;
  12166. } else {
  12167. return false;
  12168. }
  12169. };
  12170. const createRange = (sc, so, ec, eo) => {
  12171. const rng = document.createRange();
  12172. rng.setStart(sc, so);
  12173. rng.setEnd(ec, eo);
  12174. return rng;
  12175. };
  12176. const normalizeBlockSelectionRange = rng => {
  12177. const startPos = CaretPosition.fromRangeStart(rng);
  12178. const endPos = CaretPosition.fromRangeEnd(rng);
  12179. const rootNode = rng.commonAncestorContainer;
  12180. return fromPosition(false, rootNode, endPos).map(newEndPos => {
  12181. if (!isInSameBlock(startPos, endPos, rootNode) && isInSameBlock(startPos, newEndPos, rootNode)) {
  12182. return createRange(startPos.container(), startPos.offset(), newEndPos.container(), newEndPos.offset());
  12183. } else {
  12184. return rng;
  12185. }
  12186. }).getOr(rng);
  12187. };
  12188. const normalize = rng => rng.collapsed ? rng : normalizeBlockSelectionRange(rng);
  12189. const hasOnlyOneChild$1 = node => {
  12190. return isNonNullable(node.firstChild) && node.firstChild === node.lastChild;
  12191. };
  12192. const isPaddingNode = node => {
  12193. return node.name === 'br' || node.value === nbsp;
  12194. };
  12195. const isPaddedEmptyBlock = (schema, node) => {
  12196. const blockElements = schema.getBlockElements();
  12197. return blockElements[node.name] && hasOnlyOneChild$1(node) && isPaddingNode(node.firstChild);
  12198. };
  12199. const isEmptyFragmentElement = (schema, node) => {
  12200. const nonEmptyElements = schema.getNonEmptyElements();
  12201. return isNonNullable(node) && (node.isEmpty(nonEmptyElements) || isPaddedEmptyBlock(schema, node));
  12202. };
  12203. const isListFragment = (schema, fragment) => {
  12204. let firstChild = fragment.firstChild;
  12205. let lastChild = fragment.lastChild;
  12206. if (firstChild && firstChild.name === 'meta') {
  12207. firstChild = firstChild.next;
  12208. }
  12209. if (lastChild && lastChild.attr('id') === 'mce_marker') {
  12210. lastChild = lastChild.prev;
  12211. }
  12212. if (isEmptyFragmentElement(schema, lastChild)) {
  12213. lastChild = lastChild === null || lastChild === void 0 ? void 0 : lastChild.prev;
  12214. }
  12215. if (!firstChild || firstChild !== lastChild) {
  12216. return false;
  12217. }
  12218. return firstChild.name === 'ul' || firstChild.name === 'ol';
  12219. };
  12220. const cleanupDomFragment = domFragment => {
  12221. var _a, _b;
  12222. const firstChild = domFragment.firstChild;
  12223. const lastChild = domFragment.lastChild;
  12224. if (firstChild && firstChild.nodeName === 'META') {
  12225. (_a = firstChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(firstChild);
  12226. }
  12227. if (lastChild && lastChild.id === 'mce_marker') {
  12228. (_b = lastChild.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(lastChild);
  12229. }
  12230. return domFragment;
  12231. };
  12232. const toDomFragment = (dom, serializer, fragment) => {
  12233. const html = serializer.serialize(fragment);
  12234. const domFragment = dom.createFragment(html);
  12235. return cleanupDomFragment(domFragment);
  12236. };
  12237. const listItems = elm => {
  12238. var _a;
  12239. return filter$5((_a = elm === null || elm === void 0 ? void 0 : elm.childNodes) !== null && _a !== void 0 ? _a : [], child => {
  12240. return child.nodeName === 'LI';
  12241. });
  12242. };
  12243. const isPadding = node => {
  12244. return node.data === nbsp || isBr$6(node);
  12245. };
  12246. const isListItemPadded = node => {
  12247. return isNonNullable(node === null || node === void 0 ? void 0 : node.firstChild) && node.firstChild === node.lastChild && isPadding(node.firstChild);
  12248. };
  12249. const isEmptyOrPadded = elm => {
  12250. return !elm.firstChild || isListItemPadded(elm);
  12251. };
  12252. const trimListItems = elms => {
  12253. return elms.length > 0 && isEmptyOrPadded(elms[elms.length - 1]) ? elms.slice(0, -1) : elms;
  12254. };
  12255. const getParentLi = (dom, node) => {
  12256. const parentBlock = dom.getParent(node, dom.isBlock);
  12257. return parentBlock && parentBlock.nodeName === 'LI' ? parentBlock : null;
  12258. };
  12259. const isParentBlockLi = (dom, node) => {
  12260. return !!getParentLi(dom, node);
  12261. };
  12262. const getSplit = (parentNode, rng) => {
  12263. const beforeRng = rng.cloneRange();
  12264. const afterRng = rng.cloneRange();
  12265. beforeRng.setStartBefore(parentNode);
  12266. afterRng.setEndAfter(parentNode);
  12267. return [
  12268. beforeRng.cloneContents(),
  12269. afterRng.cloneContents()
  12270. ];
  12271. };
  12272. const findFirstIn = (node, rootNode) => {
  12273. const caretPos = CaretPosition.before(node);
  12274. const caretWalker = CaretWalker(rootNode);
  12275. const newCaretPos = caretWalker.next(caretPos);
  12276. return newCaretPos ? newCaretPos.toRange() : null;
  12277. };
  12278. const findLastOf = (node, rootNode) => {
  12279. const caretPos = CaretPosition.after(node);
  12280. const caretWalker = CaretWalker(rootNode);
  12281. const newCaretPos = caretWalker.prev(caretPos);
  12282. return newCaretPos ? newCaretPos.toRange() : null;
  12283. };
  12284. const insertMiddle = (target, elms, rootNode, rng) => {
  12285. const parts = getSplit(target, rng);
  12286. const parentElm = target.parentNode;
  12287. if (parentElm) {
  12288. parentElm.insertBefore(parts[0], target);
  12289. Tools.each(elms, li => {
  12290. parentElm.insertBefore(li, target);
  12291. });
  12292. parentElm.insertBefore(parts[1], target);
  12293. parentElm.removeChild(target);
  12294. }
  12295. return findLastOf(elms[elms.length - 1], rootNode);
  12296. };
  12297. const insertBefore$1 = (target, elms, rootNode) => {
  12298. const parentElm = target.parentNode;
  12299. if (parentElm) {
  12300. Tools.each(elms, elm => {
  12301. parentElm.insertBefore(elm, target);
  12302. });
  12303. }
  12304. return findFirstIn(target, rootNode);
  12305. };
  12306. const insertAfter$1 = (target, elms, rootNode, dom) => {
  12307. dom.insertAfter(elms.reverse(), target);
  12308. return findLastOf(elms[0], rootNode);
  12309. };
  12310. const insertAtCaret$1 = (serializer, dom, rng, fragment) => {
  12311. const domFragment = toDomFragment(dom, serializer, fragment);
  12312. const liTarget = getParentLi(dom, rng.startContainer);
  12313. const liElms = trimListItems(listItems(domFragment.firstChild));
  12314. const BEGINNING = 1, END = 2;
  12315. const rootNode = dom.getRoot();
  12316. const isAt = location => {
  12317. const caretPos = CaretPosition.fromRangeStart(rng);
  12318. const caretWalker = CaretWalker(dom.getRoot());
  12319. const newPos = location === BEGINNING ? caretWalker.prev(caretPos) : caretWalker.next(caretPos);
  12320. const newPosNode = newPos === null || newPos === void 0 ? void 0 : newPos.getNode();
  12321. return newPosNode ? getParentLi(dom, newPosNode) !== liTarget : true;
  12322. };
  12323. if (!liTarget) {
  12324. return null;
  12325. } else if (isAt(BEGINNING)) {
  12326. return insertBefore$1(liTarget, liElms, rootNode);
  12327. } else if (isAt(END)) {
  12328. return insertAfter$1(liTarget, liElms, rootNode, dom);
  12329. } else {
  12330. return insertMiddle(liTarget, liElms, rootNode, rng);
  12331. }
  12332. };
  12333. const mergeableWrappedElements = ['pre'];
  12334. const shouldPasteContentOnly = (dom, fragment, parentNode, root) => {
  12335. var _a;
  12336. const firstNode = fragment.firstChild;
  12337. const lastNode = fragment.lastChild;
  12338. const last = lastNode.attr('data-mce-type') === 'bookmark' ? lastNode.prev : lastNode;
  12339. const isPastingSingleElement = firstNode === last;
  12340. const isWrappedElement = contains$2(mergeableWrappedElements, firstNode.name);
  12341. if (isPastingSingleElement && isWrappedElement) {
  12342. const isContentEditable = firstNode.attr('contenteditable') !== 'false';
  12343. const isPastingInTheSameBlockTag = ((_a = dom.getParent(parentNode, dom.isBlock)) === null || _a === void 0 ? void 0 : _a.nodeName.toLowerCase()) === firstNode.name;
  12344. const isPastingInContentEditable = Optional.from(getContentEditableRoot$1(root, parentNode)).forall(isContentEditableTrue$3);
  12345. return isContentEditable && isPastingInTheSameBlockTag && isPastingInContentEditable;
  12346. } else {
  12347. return false;
  12348. }
  12349. };
  12350. const isTableCell = isTableCell$3;
  12351. const isTableCellContentSelected = (dom, rng, cell) => {
  12352. if (isNonNullable(cell)) {
  12353. const endCell = dom.getParent(rng.endContainer, isTableCell);
  12354. return cell === endCell && hasAllContentsSelected(SugarElement.fromDom(cell), rng);
  12355. } else {
  12356. return false;
  12357. }
  12358. };
  12359. const validInsertion = (editor, value, parentNode) => {
  12360. var _a;
  12361. if (parentNode.getAttribute('data-mce-bogus') === 'all') {
  12362. (_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(editor.dom.createFragment(value), parentNode);
  12363. } else {
  12364. const node = parentNode.firstChild;
  12365. const node2 = parentNode.lastChild;
  12366. if (!node || node === node2 && node.nodeName === 'BR') {
  12367. editor.dom.setHTML(parentNode, value);
  12368. } else {
  12369. editor.selection.setContent(value, { no_events: true });
  12370. }
  12371. }
  12372. };
  12373. const trimBrsFromTableCell = (dom, elm) => {
  12374. Optional.from(dom.getParent(elm, 'td,th')).map(SugarElement.fromDom).each(trimBlockTrailingBr);
  12375. };
  12376. const reduceInlineTextElements = (editor, merge) => {
  12377. const textInlineElements = editor.schema.getTextInlineElements();
  12378. const dom = editor.dom;
  12379. if (merge) {
  12380. const root = editor.getBody();
  12381. const elementUtils = ElementUtils(editor);
  12382. Tools.each(dom.select('*[data-mce-fragment]'), node => {
  12383. const isInline = isNonNullable(textInlineElements[node.nodeName.toLowerCase()]);
  12384. if (isInline && hasInheritableStyles(dom, node)) {
  12385. for (let parentNode = node.parentElement; isNonNullable(parentNode) && parentNode !== root; parentNode = parentNode.parentElement) {
  12386. const styleConflict = hasStyleConflict(dom, node, parentNode);
  12387. if (styleConflict) {
  12388. break;
  12389. }
  12390. if (elementUtils.compare(parentNode, node)) {
  12391. dom.remove(node, true);
  12392. break;
  12393. }
  12394. }
  12395. }
  12396. });
  12397. }
  12398. };
  12399. const markFragmentElements = fragment => {
  12400. let node = fragment;
  12401. while (node = node.walk()) {
  12402. if (node.type === 1) {
  12403. node.attr('data-mce-fragment', '1');
  12404. }
  12405. }
  12406. };
  12407. const unmarkFragmentElements = elm => {
  12408. Tools.each(elm.getElementsByTagName('*'), elm => {
  12409. elm.removeAttribute('data-mce-fragment');
  12410. });
  12411. };
  12412. const isPartOfFragment = node => {
  12413. return !!node.getAttribute('data-mce-fragment');
  12414. };
  12415. const canHaveChildren = (editor, node) => {
  12416. return isNonNullable(node) && !editor.schema.getVoidElements()[node.nodeName];
  12417. };
  12418. const moveSelectionToMarker = (editor, marker) => {
  12419. var _a, _b, _c;
  12420. let nextRng;
  12421. const dom = editor.dom;
  12422. const selection = editor.selection;
  12423. if (!marker) {
  12424. return;
  12425. }
  12426. selection.scrollIntoView(marker);
  12427. const parentEditableElm = getContentEditableRoot$1(editor.getBody(), marker);
  12428. if (parentEditableElm && dom.getContentEditable(parentEditableElm) === 'false') {
  12429. dom.remove(marker);
  12430. selection.select(parentEditableElm);
  12431. return;
  12432. }
  12433. let rng = dom.createRng();
  12434. const node = marker.previousSibling;
  12435. if (isText$a(node)) {
  12436. rng.setStart(node, (_b = (_a = node.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
  12437. const node2 = marker.nextSibling;
  12438. if (isText$a(node2)) {
  12439. node.appendData(node2.data);
  12440. (_c = node2.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(node2);
  12441. }
  12442. } else {
  12443. rng.setStartBefore(marker);
  12444. rng.setEndBefore(marker);
  12445. }
  12446. const findNextCaretRng = rng => {
  12447. let caretPos = CaretPosition.fromRangeStart(rng);
  12448. const caretWalker = CaretWalker(editor.getBody());
  12449. caretPos = caretWalker.next(caretPos);
  12450. return caretPos === null || caretPos === void 0 ? void 0 : caretPos.toRange();
  12451. };
  12452. const parentBlock = dom.getParent(marker, dom.isBlock);
  12453. dom.remove(marker);
  12454. if (parentBlock && dom.isEmpty(parentBlock)) {
  12455. empty(SugarElement.fromDom(parentBlock));
  12456. rng.setStart(parentBlock, 0);
  12457. rng.setEnd(parentBlock, 0);
  12458. if (!isTableCell(parentBlock) && !isPartOfFragment(parentBlock) && (nextRng = findNextCaretRng(rng))) {
  12459. rng = nextRng;
  12460. dom.remove(parentBlock);
  12461. } else {
  12462. dom.add(parentBlock, dom.create('br', { 'data-mce-bogus': '1' }));
  12463. }
  12464. }
  12465. selection.setRng(rng);
  12466. };
  12467. const deleteSelectedContent = editor => {
  12468. const dom = editor.dom;
  12469. const rng = normalize(editor.selection.getRng());
  12470. editor.selection.setRng(rng);
  12471. const startCell = dom.getParent(rng.startContainer, isTableCell);
  12472. if (isTableCellContentSelected(dom, rng, startCell)) {
  12473. deleteCellContents(editor, rng, SugarElement.fromDom(startCell));
  12474. } else if (rng.startContainer === rng.endContainer && rng.endOffset - rng.startOffset === 1 && isText$a(rng.startContainer.childNodes[rng.startOffset])) {
  12475. rng.deleteContents();
  12476. } else {
  12477. editor.getDoc().execCommand('Delete', false);
  12478. }
  12479. };
  12480. const insertHtmlAtCaret = (editor, value, details) => {
  12481. var _a, _b;
  12482. const selection = editor.selection;
  12483. const dom = editor.dom;
  12484. const parser = editor.parser;
  12485. const merge = details.merge;
  12486. const serializer = HtmlSerializer({ validate: true }, editor.schema);
  12487. const bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">&#xFEFF;</span>';
  12488. if (value.indexOf('{$caret}') === -1) {
  12489. value += '{$caret}';
  12490. }
  12491. value = value.replace(/\{\$caret\}/, bookmarkHtml);
  12492. let rng = selection.getRng();
  12493. const caretElement = rng.startContainer;
  12494. const body = editor.getBody();
  12495. if (caretElement === body && selection.isCollapsed()) {
  12496. if (dom.isBlock(body.firstChild) && canHaveChildren(editor, body.firstChild) && dom.isEmpty(body.firstChild)) {
  12497. rng = dom.createRng();
  12498. rng.setStart(body.firstChild, 0);
  12499. rng.setEnd(body.firstChild, 0);
  12500. selection.setRng(rng);
  12501. }
  12502. }
  12503. if (!selection.isCollapsed()) {
  12504. deleteSelectedContent(editor);
  12505. }
  12506. const parentNode = selection.getNode();
  12507. const parserArgs = {
  12508. context: parentNode.nodeName.toLowerCase(),
  12509. data: details.data,
  12510. insert: true
  12511. };
  12512. const fragment = parser.parse(value, parserArgs);
  12513. if (details.paste === true && isListFragment(editor.schema, fragment) && isParentBlockLi(dom, parentNode)) {
  12514. rng = insertAtCaret$1(serializer, dom, selection.getRng(), fragment);
  12515. if (rng) {
  12516. selection.setRng(rng);
  12517. }
  12518. return value;
  12519. }
  12520. if (details.paste === true && shouldPasteContentOnly(dom, fragment, parentNode, editor.getBody())) {
  12521. (_a = fragment.firstChild) === null || _a === void 0 ? void 0 : _a.unwrap();
  12522. }
  12523. markFragmentElements(fragment);
  12524. let node = fragment.lastChild;
  12525. if (node && node.attr('id') === 'mce_marker') {
  12526. const marker = node;
  12527. for (node = node.prev; node; node = node.walk(true)) {
  12528. if (node.type === 3 || !dom.isBlock(node.name)) {
  12529. if (node.parent && editor.schema.isValidChild(node.parent.name, 'span')) {
  12530. node.parent.insert(marker, node, node.name === 'br');
  12531. }
  12532. break;
  12533. }
  12534. }
  12535. }
  12536. editor._selectionOverrides.showBlockCaretContainer(parentNode);
  12537. if (!parserArgs.invalid) {
  12538. value = serializer.serialize(fragment);
  12539. validInsertion(editor, value, parentNode);
  12540. } else {
  12541. editor.selection.setContent(bookmarkHtml);
  12542. let parentNode = selection.getNode();
  12543. let tempNode;
  12544. const rootNode = editor.getBody();
  12545. if (isDocument$1(parentNode)) {
  12546. parentNode = tempNode = rootNode;
  12547. } else {
  12548. tempNode = parentNode;
  12549. }
  12550. while (tempNode && tempNode !== rootNode) {
  12551. parentNode = tempNode;
  12552. tempNode = tempNode.parentNode;
  12553. }
  12554. value = parentNode === rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
  12555. const root = parser.parse(value);
  12556. for (let markerNode = root; markerNode; markerNode = markerNode.walk()) {
  12557. if (markerNode.attr('id') === 'mce_marker') {
  12558. markerNode.replace(fragment);
  12559. break;
  12560. }
  12561. }
  12562. const toExtract = fragment.children();
  12563. const parent = (_b = fragment.parent) !== null && _b !== void 0 ? _b : root;
  12564. fragment.unwrap();
  12565. const invalidChildren = filter$5(toExtract, node => isInvalid(editor.schema, node, parent));
  12566. cleanInvalidNodes(invalidChildren, editor.schema);
  12567. filter$2(parser.getNodeFilters(), parser.getAttributeFilters(), root);
  12568. value = serializer.serialize(root);
  12569. if (parentNode === rootNode) {
  12570. dom.setHTML(rootNode, value);
  12571. } else {
  12572. dom.setOuterHTML(parentNode, value);
  12573. }
  12574. }
  12575. reduceInlineTextElements(editor, merge);
  12576. moveSelectionToMarker(editor, dom.get('mce_marker'));
  12577. unmarkFragmentElements(editor.getBody());
  12578. trimBrsFromTableCell(dom, selection.getStart());
  12579. updateCaret(editor.schema, editor.getBody(), selection.getStart());
  12580. return value;
  12581. };
  12582. const isTreeNode = content => content instanceof AstNode;
  12583. const moveSelection = editor => {
  12584. if (hasFocus(editor)) {
  12585. firstPositionIn(editor.getBody()).each(pos => {
  12586. const node = pos.getNode();
  12587. const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
  12588. editor.selection.setRng(caretPos.toRange());
  12589. });
  12590. }
  12591. };
  12592. const setEditorHtml = (editor, html, noSelection) => {
  12593. editor.dom.setHTML(editor.getBody(), html);
  12594. if (noSelection !== true) {
  12595. moveSelection(editor);
  12596. }
  12597. };
  12598. const setContentString = (editor, body, content, args) => {
  12599. if (content.length === 0 || /^\s+$/.test(content)) {
  12600. const padd = '<br data-mce-bogus="1">';
  12601. if (body.nodeName === 'TABLE') {
  12602. content = '<tr><td>' + padd + '</td></tr>';
  12603. } else if (/^(UL|OL)$/.test(body.nodeName)) {
  12604. content = '<li>' + padd + '</li>';
  12605. }
  12606. const forcedRootBlockName = getForcedRootBlock(editor);
  12607. if (editor.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
  12608. content = padd;
  12609. content = editor.dom.createHTML(forcedRootBlockName, getForcedRootBlockAttrs(editor), content);
  12610. } else if (!content) {
  12611. content = padd;
  12612. }
  12613. setEditorHtml(editor, content, args.no_selection);
  12614. return {
  12615. content,
  12616. html: content
  12617. };
  12618. } else {
  12619. if (args.format !== 'raw') {
  12620. content = HtmlSerializer({ validate: false }, editor.schema).serialize(editor.parser.parse(content, {
  12621. isRootContent: true,
  12622. insert: true
  12623. }));
  12624. }
  12625. const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? content : Tools.trim(content);
  12626. setEditorHtml(editor, trimmedHtml, args.no_selection);
  12627. return {
  12628. content: trimmedHtml,
  12629. html: trimmedHtml
  12630. };
  12631. }
  12632. };
  12633. const setContentTree = (editor, body, content, args) => {
  12634. filter$2(editor.parser.getNodeFilters(), editor.parser.getAttributeFilters(), content);
  12635. const html = HtmlSerializer({ validate: false }, editor.schema).serialize(content);
  12636. const trimmedHtml = isWsPreserveElement(SugarElement.fromDom(body)) ? html : Tools.trim(html);
  12637. setEditorHtml(editor, trimmedHtml, args.no_selection);
  12638. return {
  12639. content,
  12640. html: trimmedHtml
  12641. };
  12642. };
  12643. const setContentInternal = (editor, content, args) => {
  12644. return Optional.from(editor.getBody()).map(body => {
  12645. if (isTreeNode(content)) {
  12646. return setContentTree(editor, body, content, args);
  12647. } else {
  12648. return setContentString(editor, body, content, args);
  12649. }
  12650. }).getOr({
  12651. content,
  12652. html: isTreeNode(args.content) ? '' : args.content
  12653. });
  12654. };
  12655. const sibling = (scope, predicate) => sibling$1(scope, predicate).isSome();
  12656. const ensureIsRoot = isRoot => isFunction(isRoot) ? isRoot : never;
  12657. const ancestor = (scope, transform, isRoot) => {
  12658. let element = scope.dom;
  12659. const stop = ensureIsRoot(isRoot);
  12660. while (element.parentNode) {
  12661. element = element.parentNode;
  12662. const el = SugarElement.fromDom(element);
  12663. const transformed = transform(el);
  12664. if (transformed.isSome()) {
  12665. return transformed;
  12666. } else if (stop(el)) {
  12667. break;
  12668. }
  12669. }
  12670. return Optional.none();
  12671. };
  12672. const closest$2 = (scope, transform, isRoot) => {
  12673. const current = transform(scope);
  12674. const stop = ensureIsRoot(isRoot);
  12675. return current.orThunk(() => stop(scope) ? Optional.none() : ancestor(scope, transform, stop));
  12676. };
  12677. const isEq$3 = isEq$5;
  12678. const matchesUnInheritedFormatSelector = (ed, node, name) => {
  12679. const formatList = ed.formatter.get(name);
  12680. if (formatList) {
  12681. for (let i = 0; i < formatList.length; i++) {
  12682. const format = formatList[i];
  12683. if (isSelectorFormat(format) && format.inherit === false && ed.dom.is(node, format.selector)) {
  12684. return true;
  12685. }
  12686. }
  12687. }
  12688. return false;
  12689. };
  12690. const matchParents = (editor, node, name, vars, similar) => {
  12691. const root = editor.dom.getRoot();
  12692. if (node === root) {
  12693. return false;
  12694. }
  12695. const matchedNode = editor.dom.getParent(node, elm => {
  12696. if (matchesUnInheritedFormatSelector(editor, elm, name)) {
  12697. return true;
  12698. }
  12699. return elm.parentNode === root || !!matchNode(editor, elm, name, vars, true);
  12700. });
  12701. return !!matchNode(editor, matchedNode, name, vars, similar);
  12702. };
  12703. const matchName = (dom, node, format) => {
  12704. if (isInlineFormat(format) && isEq$3(node, format.inline)) {
  12705. return true;
  12706. }
  12707. if (isBlockFormat(format) && isEq$3(node, format.block)) {
  12708. return true;
  12709. }
  12710. if (isSelectorFormat(format)) {
  12711. return isElement$6(node) && dom.is(node, format.selector);
  12712. }
  12713. return false;
  12714. };
  12715. const matchItems = (dom, node, format, itemName, similar, vars) => {
  12716. const items = format[itemName];
  12717. const matchAttributes = itemName === 'attributes';
  12718. if (isFunction(format.onmatch)) {
  12719. return format.onmatch(node, format, itemName);
  12720. }
  12721. if (items) {
  12722. if (!isArrayLike(items)) {
  12723. for (const key in items) {
  12724. if (has$2(items, key)) {
  12725. const value = matchAttributes ? dom.getAttrib(node, key) : getStyle(dom, node, key);
  12726. const expectedValue = replaceVars(items[key], vars);
  12727. const isEmptyValue = isNullable(value) || isEmpty$3(value);
  12728. if (isEmptyValue && isNullable(expectedValue)) {
  12729. continue;
  12730. }
  12731. if (similar && isEmptyValue && !format.exact) {
  12732. return false;
  12733. }
  12734. if ((!similar || format.exact) && !isEq$3(value, normalizeStyleValue(expectedValue, key))) {
  12735. return false;
  12736. }
  12737. }
  12738. }
  12739. } else {
  12740. for (let i = 0; i < items.length; i++) {
  12741. if (matchAttributes ? dom.getAttrib(node, items[i]) : getStyle(dom, node, items[i])) {
  12742. return true;
  12743. }
  12744. }
  12745. }
  12746. }
  12747. return true;
  12748. };
  12749. const matchNode = (ed, node, name, vars, similar) => {
  12750. const formatList = ed.formatter.get(name);
  12751. const dom = ed.dom;
  12752. if (formatList && isElement$6(node)) {
  12753. for (let i = 0; i < formatList.length; i++) {
  12754. const format = formatList[i];
  12755. if (matchName(ed.dom, node, format) && matchItems(dom, node, format, 'attributes', similar, vars) && matchItems(dom, node, format, 'styles', similar, vars)) {
  12756. const classes = format.classes;
  12757. if (classes) {
  12758. for (let x = 0; x < classes.length; x++) {
  12759. if (!ed.dom.hasClass(node, replaceVars(classes[x], vars))) {
  12760. return;
  12761. }
  12762. }
  12763. }
  12764. return format;
  12765. }
  12766. }
  12767. }
  12768. return undefined;
  12769. };
  12770. const match$2 = (editor, name, vars, node, similar) => {
  12771. if (node) {
  12772. return matchParents(editor, node, name, vars, similar);
  12773. }
  12774. node = editor.selection.getNode();
  12775. if (matchParents(editor, node, name, vars, similar)) {
  12776. return true;
  12777. }
  12778. const startNode = editor.selection.getStart();
  12779. if (startNode !== node) {
  12780. if (matchParents(editor, startNode, name, vars, similar)) {
  12781. return true;
  12782. }
  12783. }
  12784. return false;
  12785. };
  12786. const matchAll = (editor, names, vars) => {
  12787. const matchedFormatNames = [];
  12788. const checkedMap = {};
  12789. const startElement = editor.selection.getStart();
  12790. editor.dom.getParent(startElement, node => {
  12791. for (let i = 0; i < names.length; i++) {
  12792. const name = names[i];
  12793. if (!checkedMap[name] && matchNode(editor, node, name, vars)) {
  12794. checkedMap[name] = true;
  12795. matchedFormatNames.push(name);
  12796. }
  12797. }
  12798. }, editor.dom.getRoot());
  12799. return matchedFormatNames;
  12800. };
  12801. const closest$1 = (editor, names) => {
  12802. const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
  12803. const match = (elm, name) => matchNode(editor, elm.dom, name) ? Optional.some(name) : Optional.none();
  12804. return Optional.from(editor.selection.getStart(true)).bind(rawElm => closest$2(SugarElement.fromDom(rawElm), elm => findMap(names, name => match(elm, name)), isRoot)).getOrNull();
  12805. };
  12806. const canApply = (editor, name) => {
  12807. const formatList = editor.formatter.get(name);
  12808. const dom = editor.dom;
  12809. if (formatList) {
  12810. const startNode = editor.selection.getStart();
  12811. const parents = getParents$2(dom, startNode);
  12812. for (let x = formatList.length - 1; x >= 0; x--) {
  12813. const format = formatList[x];
  12814. if (!isSelectorFormat(format)) {
  12815. return true;
  12816. }
  12817. for (let i = parents.length - 1; i >= 0; i--) {
  12818. if (dom.is(parents[i], format.selector)) {
  12819. return true;
  12820. }
  12821. }
  12822. }
  12823. }
  12824. return false;
  12825. };
  12826. const matchAllOnNode = (editor, node, formatNames) => foldl(formatNames, (acc, name) => {
  12827. const matchSimilar = isVariableFormatName(editor, name);
  12828. if (editor.formatter.matchNode(node, name, {}, matchSimilar)) {
  12829. return acc.concat([name]);
  12830. } else {
  12831. return acc;
  12832. }
  12833. }, []);
  12834. const ZWSP = ZWSP$1;
  12835. const importNode = (ownerDocument, node) => {
  12836. return ownerDocument.importNode(node, true);
  12837. };
  12838. const getEmptyCaretContainers = node => {
  12839. const nodes = [];
  12840. let tempNode = node;
  12841. while (tempNode) {
  12842. if (isText$a(tempNode) && tempNode.data !== ZWSP || tempNode.childNodes.length > 1) {
  12843. return [];
  12844. }
  12845. if (isElement$6(tempNode)) {
  12846. nodes.push(tempNode);
  12847. }
  12848. tempNode = tempNode.firstChild;
  12849. }
  12850. return nodes;
  12851. };
  12852. const isCaretContainerEmpty = node => {
  12853. return getEmptyCaretContainers(node).length > 0;
  12854. };
  12855. const findFirstTextNode = node => {
  12856. if (node) {
  12857. const walker = new DomTreeWalker(node, node);
  12858. for (let tempNode = walker.current(); tempNode; tempNode = walker.next()) {
  12859. if (isText$a(tempNode)) {
  12860. return tempNode;
  12861. }
  12862. }
  12863. }
  12864. return null;
  12865. };
  12866. const createCaretContainer = fill => {
  12867. const caretContainer = SugarElement.fromTag('span');
  12868. setAll$1(caretContainer, {
  12869. 'id': CARET_ID,
  12870. 'data-mce-bogus': '1',
  12871. 'data-mce-type': 'format-caret'
  12872. });
  12873. if (fill) {
  12874. append$1(caretContainer, SugarElement.fromText(ZWSP));
  12875. }
  12876. return caretContainer;
  12877. };
  12878. const trimZwspFromCaretContainer = caretContainerNode => {
  12879. const textNode = findFirstTextNode(caretContainerNode);
  12880. if (textNode && textNode.data.charAt(0) === ZWSP) {
  12881. textNode.deleteData(0, 1);
  12882. }
  12883. return textNode;
  12884. };
  12885. const removeCaretContainerNode = (editor, node, moveCaret = true) => {
  12886. const dom = editor.dom, selection = editor.selection;
  12887. if (isCaretContainerEmpty(node)) {
  12888. deleteElement$2(editor, false, SugarElement.fromDom(node), moveCaret);
  12889. } else {
  12890. const rng = selection.getRng();
  12891. const block = dom.getParent(node, dom.isBlock);
  12892. const startContainer = rng.startContainer;
  12893. const startOffset = rng.startOffset;
  12894. const endContainer = rng.endContainer;
  12895. const endOffset = rng.endOffset;
  12896. const textNode = trimZwspFromCaretContainer(node);
  12897. dom.remove(node, true);
  12898. if (startContainer === textNode && startOffset > 0) {
  12899. rng.setStart(textNode, startOffset - 1);
  12900. }
  12901. if (endContainer === textNode && endOffset > 0) {
  12902. rng.setEnd(textNode, endOffset - 1);
  12903. }
  12904. if (block && dom.isEmpty(block)) {
  12905. fillWithPaddingBr(SugarElement.fromDom(block));
  12906. }
  12907. selection.setRng(rng);
  12908. }
  12909. };
  12910. const removeCaretContainer = (editor, node, moveCaret = true) => {
  12911. const dom = editor.dom, selection = editor.selection;
  12912. if (!node) {
  12913. node = getParentCaretContainer(editor.getBody(), selection.getStart());
  12914. if (!node) {
  12915. while (node = dom.get(CARET_ID)) {
  12916. removeCaretContainerNode(editor, node, false);
  12917. }
  12918. }
  12919. } else {
  12920. removeCaretContainerNode(editor, node, moveCaret);
  12921. }
  12922. };
  12923. const insertCaretContainerNode = (editor, caretContainer, formatNode) => {
  12924. var _a, _b;
  12925. const dom = editor.dom;
  12926. const block = dom.getParent(formatNode, curry(isTextBlock$1, editor.schema));
  12927. if (block && dom.isEmpty(block)) {
  12928. (_a = formatNode.parentNode) === null || _a === void 0 ? void 0 : _a.replaceChild(caretContainer, formatNode);
  12929. } else {
  12930. removeTrailingBr(SugarElement.fromDom(formatNode));
  12931. if (dom.isEmpty(formatNode)) {
  12932. (_b = formatNode.parentNode) === null || _b === void 0 ? void 0 : _b.replaceChild(caretContainer, formatNode);
  12933. } else {
  12934. dom.insertAfter(caretContainer, formatNode);
  12935. }
  12936. }
  12937. };
  12938. const appendNode = (parentNode, node) => {
  12939. parentNode.appendChild(node);
  12940. return node;
  12941. };
  12942. const insertFormatNodesIntoCaretContainer = (formatNodes, caretContainer) => {
  12943. var _a;
  12944. const innerMostFormatNode = foldr(formatNodes, (parentNode, formatNode) => {
  12945. return appendNode(parentNode, formatNode.cloneNode(false));
  12946. }, caretContainer);
  12947. const doc = (_a = innerMostFormatNode.ownerDocument) !== null && _a !== void 0 ? _a : document;
  12948. return appendNode(innerMostFormatNode, doc.createTextNode(ZWSP));
  12949. };
  12950. const cleanFormatNode = (editor, caretContainer, formatNode, name, vars, similar) => {
  12951. const formatter = editor.formatter;
  12952. const dom = editor.dom;
  12953. const validFormats = filter$5(keys(formatter.get()), formatName => formatName !== name && !contains$1(formatName, 'removeformat'));
  12954. const matchedFormats = matchAllOnNode(editor, formatNode, validFormats);
  12955. const uniqueFormats = filter$5(matchedFormats, fmtName => !areSimilarFormats(editor, fmtName, name));
  12956. if (uniqueFormats.length > 0) {
  12957. const clonedFormatNode = formatNode.cloneNode(false);
  12958. dom.add(caretContainer, clonedFormatNode);
  12959. formatter.remove(name, vars, clonedFormatNode, similar);
  12960. dom.remove(clonedFormatNode);
  12961. return Optional.some(clonedFormatNode);
  12962. } else {
  12963. return Optional.none();
  12964. }
  12965. };
  12966. const applyCaretFormat = (editor, name, vars) => {
  12967. let caretContainer;
  12968. const selection = editor.selection;
  12969. const formatList = editor.formatter.get(name);
  12970. if (!formatList) {
  12971. return;
  12972. }
  12973. const selectionRng = selection.getRng();
  12974. let offset = selectionRng.startOffset;
  12975. const container = selectionRng.startContainer;
  12976. const text = container.nodeValue;
  12977. caretContainer = getParentCaretContainer(editor.getBody(), selection.getStart());
  12978. const wordcharRegex = /[^\s\u00a0\u00ad\u200b\ufeff]/;
  12979. if (text && offset > 0 && offset < text.length && wordcharRegex.test(text.charAt(offset)) && wordcharRegex.test(text.charAt(offset - 1))) {
  12980. const bookmark = selection.getBookmark();
  12981. selectionRng.collapse(true);
  12982. let rng = expandRng(editor.dom, selectionRng, formatList);
  12983. rng = split(rng);
  12984. editor.formatter.apply(name, vars, rng);
  12985. selection.moveToBookmark(bookmark);
  12986. } else {
  12987. let textNode = caretContainer ? findFirstTextNode(caretContainer) : null;
  12988. if (!caretContainer || (textNode === null || textNode === void 0 ? void 0 : textNode.data) !== ZWSP) {
  12989. caretContainer = importNode(editor.getDoc(), createCaretContainer(true).dom);
  12990. textNode = caretContainer.firstChild;
  12991. selectionRng.insertNode(caretContainer);
  12992. offset = 1;
  12993. editor.formatter.apply(name, vars, caretContainer);
  12994. } else {
  12995. editor.formatter.apply(name, vars, caretContainer);
  12996. }
  12997. selection.setCursorLocation(textNode, offset);
  12998. }
  12999. };
  13000. const removeCaretFormat = (editor, name, vars, similar) => {
  13001. const dom = editor.dom;
  13002. const selection = editor.selection;
  13003. let hasContentAfter = false;
  13004. const formatList = editor.formatter.get(name);
  13005. if (!formatList) {
  13006. return;
  13007. }
  13008. const rng = selection.getRng();
  13009. const container = rng.startContainer;
  13010. const offset = rng.startOffset;
  13011. let node = container;
  13012. if (isText$a(container)) {
  13013. if (offset !== container.data.length) {
  13014. hasContentAfter = true;
  13015. }
  13016. node = node.parentNode;
  13017. }
  13018. const parents = [];
  13019. let formatNode;
  13020. while (node) {
  13021. if (matchNode(editor, node, name, vars, similar)) {
  13022. formatNode = node;
  13023. break;
  13024. }
  13025. if (node.nextSibling) {
  13026. hasContentAfter = true;
  13027. }
  13028. parents.push(node);
  13029. node = node.parentNode;
  13030. }
  13031. if (!formatNode) {
  13032. return;
  13033. }
  13034. if (hasContentAfter) {
  13035. const bookmark = selection.getBookmark();
  13036. rng.collapse(true);
  13037. let expandedRng = expandRng(dom, rng, formatList, true);
  13038. expandedRng = split(expandedRng);
  13039. editor.formatter.remove(name, vars, expandedRng, similar);
  13040. selection.moveToBookmark(bookmark);
  13041. } else {
  13042. const caretContainer = getParentCaretContainer(editor.getBody(), formatNode);
  13043. const newCaretContainer = createCaretContainer(false).dom;
  13044. insertCaretContainerNode(editor, newCaretContainer, caretContainer !== null && caretContainer !== void 0 ? caretContainer : formatNode);
  13045. const cleanedFormatNode = cleanFormatNode(editor, newCaretContainer, formatNode, name, vars, similar);
  13046. const caretTextNode = insertFormatNodesIntoCaretContainer(parents.concat(cleanedFormatNode.toArray()), newCaretContainer);
  13047. if (caretContainer) {
  13048. removeCaretContainerNode(editor, caretContainer, false);
  13049. }
  13050. selection.setCursorLocation(caretTextNode, 1);
  13051. if (dom.isEmpty(formatNode)) {
  13052. dom.remove(formatNode);
  13053. }
  13054. }
  13055. };
  13056. const disableCaretContainer = (editor, keyCode) => {
  13057. const selection = editor.selection, body = editor.getBody();
  13058. removeCaretContainer(editor, null, false);
  13059. if ((keyCode === 8 || keyCode === 46) && selection.isCollapsed() && selection.getStart().innerHTML === ZWSP) {
  13060. removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
  13061. }
  13062. if (keyCode === 37 || keyCode === 39) {
  13063. removeCaretContainer(editor, getParentCaretContainer(body, selection.getStart()));
  13064. }
  13065. };
  13066. const setup$u = editor => {
  13067. editor.on('mouseup keydown', e => {
  13068. disableCaretContainer(editor, e.keyCode);
  13069. });
  13070. };
  13071. const replaceWithCaretFormat = (targetNode, formatNodes) => {
  13072. const caretContainer = createCaretContainer(false);
  13073. const innerMost = insertFormatNodesIntoCaretContainer(formatNodes, caretContainer.dom);
  13074. before$3(SugarElement.fromDom(targetNode), caretContainer);
  13075. remove$6(SugarElement.fromDom(targetNode));
  13076. return CaretPosition(innerMost, 0);
  13077. };
  13078. const isFormatElement = (editor, element) => {
  13079. const inlineElements = editor.schema.getTextInlineElements();
  13080. return has$2(inlineElements, name(element)) && !isCaretNode(element.dom) && !isBogus$2(element.dom);
  13081. };
  13082. const isEmptyCaretFormatElement = element => {
  13083. return isCaretNode(element.dom) && isCaretContainerEmpty(element.dom);
  13084. };
  13085. const postProcessHooks = {};
  13086. const isPre = matchNodeNames(['pre']);
  13087. const addPostProcessHook = (name, hook) => {
  13088. const hooks = postProcessHooks[name];
  13089. if (!hooks) {
  13090. postProcessHooks[name] = [];
  13091. }
  13092. postProcessHooks[name].push(hook);
  13093. };
  13094. const postProcess$1 = (name, editor) => {
  13095. if (has$2(postProcessHooks, name)) {
  13096. each$e(postProcessHooks[name], hook => {
  13097. hook(editor);
  13098. });
  13099. }
  13100. };
  13101. addPostProcessHook('pre', editor => {
  13102. const rng = editor.selection.getRng();
  13103. const hasPreSibling = blocks => pre => {
  13104. const prev = pre.previousSibling;
  13105. return isPre(prev) && contains$2(blocks, prev);
  13106. };
  13107. const joinPre = (pre1, pre2) => {
  13108. const sPre2 = SugarElement.fromDom(pre2);
  13109. const doc = documentOrOwner(sPre2).dom;
  13110. remove$6(sPre2);
  13111. append(SugarElement.fromDom(pre1), [
  13112. SugarElement.fromTag('br', doc),
  13113. SugarElement.fromTag('br', doc),
  13114. ...children$1(sPre2)
  13115. ]);
  13116. };
  13117. if (!rng.collapsed) {
  13118. const blocks = editor.selection.getSelectedBlocks();
  13119. const preBlocks = filter$5(filter$5(blocks, isPre), hasPreSibling(blocks));
  13120. each$e(preBlocks, pre => {
  13121. joinPre(pre.previousSibling, pre);
  13122. });
  13123. }
  13124. });
  13125. const listItemStyles = [
  13126. 'fontWeight',
  13127. 'fontStyle',
  13128. 'color',
  13129. 'fontSize',
  13130. 'fontFamily'
  13131. ];
  13132. const hasListStyles = fmt => isObject(fmt.styles) && exists(keys(fmt.styles), name => contains$2(listItemStyles, name));
  13133. const findExpandedListItemFormat = formats => find$2(formats, fmt => isInlineFormat(fmt) && fmt.inline === 'span' && hasListStyles(fmt));
  13134. const getExpandedListItemFormat = (formatter, format) => {
  13135. const formatList = formatter.get(format);
  13136. return isArray$1(formatList) ? findExpandedListItemFormat(formatList) : Optional.none();
  13137. };
  13138. const isRngStartAtStartOfElement = (rng, elm) => prevPosition(elm, CaretPosition.fromRangeStart(rng)).isNone();
  13139. const isRngEndAtEndOfElement = (rng, elm) => {
  13140. return nextPosition(elm, CaretPosition.fromRangeEnd(rng)).exists(pos => !isBr$6(pos.getNode()) || nextPosition(elm, pos).isSome()) === false;
  13141. };
  13142. const isEditableListItem = dom => elm => isListItem$2(elm) && dom.getContentEditableParent(elm) !== 'false';
  13143. const getFullySelectedBlocks = selection => {
  13144. const blocks = selection.getSelectedBlocks();
  13145. const rng = selection.getRng();
  13146. if (selection.isCollapsed()) {
  13147. return [];
  13148. }
  13149. if (blocks.length === 1) {
  13150. return isRngStartAtStartOfElement(rng, blocks[0]) && isRngEndAtEndOfElement(rng, blocks[0]) ? blocks : [];
  13151. } else {
  13152. const first = head(blocks).filter(elm => isRngStartAtStartOfElement(rng, elm)).toArray();
  13153. const last = last$3(blocks).filter(elm => isRngEndAtEndOfElement(rng, elm)).toArray();
  13154. const middle = blocks.slice(1, -1);
  13155. return first.concat(middle).concat(last);
  13156. }
  13157. };
  13158. const getFullySelectedListItems = selection => filter$5(getFullySelectedBlocks(selection), isEditableListItem(selection.dom));
  13159. const getPartiallySelectedListItems = selection => filter$5(selection.getSelectedBlocks(), isEditableListItem(selection.dom));
  13160. const each$8 = Tools.each;
  13161. const isElementNode = node => isElement$6(node) && !isBookmarkNode$1(node) && !isCaretNode(node) && !isBogus$2(node);
  13162. const findElementSibling = (node, siblingName) => {
  13163. for (let sibling = node; sibling; sibling = sibling[siblingName]) {
  13164. if (isText$a(sibling) && isNotEmpty(sibling.data)) {
  13165. return node;
  13166. }
  13167. if (isElement$6(sibling) && !isBookmarkNode$1(sibling)) {
  13168. return sibling;
  13169. }
  13170. }
  13171. return node;
  13172. };
  13173. const mergeSiblingsNodes = (editor, prev, next) => {
  13174. const elementUtils = ElementUtils(editor);
  13175. const isPrevEditable = isElement$6(prev) && isEditable$3(prev);
  13176. const isNextEditable = isElement$6(next) && isEditable$3(next);
  13177. if (isPrevEditable && isNextEditable) {
  13178. const prevSibling = findElementSibling(prev, 'previousSibling');
  13179. const nextSibling = findElementSibling(next, 'nextSibling');
  13180. if (elementUtils.compare(prevSibling, nextSibling)) {
  13181. for (let sibling = prevSibling.nextSibling; sibling && sibling !== nextSibling;) {
  13182. const tmpSibling = sibling;
  13183. sibling = sibling.nextSibling;
  13184. prevSibling.appendChild(tmpSibling);
  13185. }
  13186. editor.dom.remove(nextSibling);
  13187. Tools.each(Tools.grep(nextSibling.childNodes), node => {
  13188. prevSibling.appendChild(node);
  13189. });
  13190. return prevSibling;
  13191. }
  13192. }
  13193. return next;
  13194. };
  13195. const mergeSiblings = (editor, format, vars, node) => {
  13196. var _a;
  13197. if (node && format.merge_siblings !== false) {
  13198. const newNode = (_a = mergeSiblingsNodes(editor, getNonWhiteSpaceSibling(node), node)) !== null && _a !== void 0 ? _a : node;
  13199. mergeSiblingsNodes(editor, newNode, getNonWhiteSpaceSibling(newNode, true));
  13200. }
  13201. };
  13202. const clearChildStyles = (dom, format, node) => {
  13203. if (format.clear_child_styles) {
  13204. const selector = format.links ? '*:not(a)' : '*';
  13205. each$8(dom.select(selector, node), childNode => {
  13206. if (isElementNode(childNode) && isEditable$3(childNode)) {
  13207. each$8(format.styles, (_value, name) => {
  13208. dom.setStyle(childNode, name, '');
  13209. });
  13210. }
  13211. });
  13212. }
  13213. };
  13214. const processChildElements = (node, filter, process) => {
  13215. each$8(node.childNodes, node => {
  13216. if (isElementNode(node)) {
  13217. if (filter(node)) {
  13218. process(node);
  13219. }
  13220. if (node.hasChildNodes()) {
  13221. processChildElements(node, filter, process);
  13222. }
  13223. }
  13224. });
  13225. };
  13226. const unwrapEmptySpan = (dom, node) => {
  13227. if (node.nodeName === 'SPAN' && dom.getAttribs(node).length === 0) {
  13228. dom.remove(node, true);
  13229. }
  13230. };
  13231. const hasStyle = (dom, name) => node => !!(node && getStyle(dom, node, name));
  13232. const applyStyle = (dom, name, value) => node => {
  13233. dom.setStyle(node, name, value);
  13234. if (node.getAttribute('style') === '') {
  13235. node.removeAttribute('style');
  13236. }
  13237. unwrapEmptySpan(dom, node);
  13238. };
  13239. const removeResult = Adt.generate([
  13240. { keep: [] },
  13241. { rename: ['name'] },
  13242. { removed: [] }
  13243. ]);
  13244. const MCE_ATTR_RE = /^(src|href|style)$/;
  13245. const each$7 = Tools.each;
  13246. const isEq$2 = isEq$5;
  13247. const isTableCellOrRow = node => /^(TR|TH|TD)$/.test(node.nodeName);
  13248. const isChildOfInlineParent = (dom, node, parent) => dom.isChildOf(node, parent) && node !== parent && !dom.isBlock(parent);
  13249. const getContainer = (ed, rng, start) => {
  13250. let container = rng[start ? 'startContainer' : 'endContainer'];
  13251. let offset = rng[start ? 'startOffset' : 'endOffset'];
  13252. if (isElement$6(container)) {
  13253. const lastIdx = container.childNodes.length - 1;
  13254. if (!start && offset) {
  13255. offset--;
  13256. }
  13257. container = container.childNodes[offset > lastIdx ? lastIdx : offset];
  13258. }
  13259. if (isText$a(container) && start && offset >= container.data.length) {
  13260. container = new DomTreeWalker(container, ed.getBody()).next() || container;
  13261. }
  13262. if (isText$a(container) && !start && offset === 0) {
  13263. container = new DomTreeWalker(container, ed.getBody()).prev() || container;
  13264. }
  13265. return container;
  13266. };
  13267. const normalizeTableSelection = (node, start) => {
  13268. const prop = start ? 'firstChild' : 'lastChild';
  13269. const childNode = node[prop];
  13270. if (isTableCellOrRow(node) && childNode) {
  13271. if (node.nodeName === 'TR') {
  13272. return childNode[prop] || childNode;
  13273. } else {
  13274. return childNode;
  13275. }
  13276. }
  13277. return node;
  13278. };
  13279. const wrap$1 = (dom, node, name, attrs) => {
  13280. var _a;
  13281. const wrapper = dom.create(name, attrs);
  13282. (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(wrapper, node);
  13283. wrapper.appendChild(node);
  13284. return wrapper;
  13285. };
  13286. const wrapWithSiblings = (dom, node, next, name, attrs) => {
  13287. const start = SugarElement.fromDom(node);
  13288. const wrapper = SugarElement.fromDom(dom.create(name, attrs));
  13289. const siblings = next ? nextSiblings(start) : prevSiblings(start);
  13290. append(wrapper, siblings);
  13291. if (next) {
  13292. before$3(start, wrapper);
  13293. prepend(wrapper, start);
  13294. } else {
  13295. after$4(start, wrapper);
  13296. append$1(wrapper, start);
  13297. }
  13298. return wrapper.dom;
  13299. };
  13300. const isColorFormatAndAnchor = (node, format) => format.links && node.nodeName === 'A';
  13301. const removeNode = (ed, node, format) => {
  13302. const parentNode = node.parentNode;
  13303. let rootBlockElm;
  13304. const dom = ed.dom;
  13305. const forcedRootBlock = getForcedRootBlock(ed);
  13306. if (isBlockFormat(format)) {
  13307. if (parentNode === dom.getRoot()) {
  13308. if (!format.list_block || !isEq$2(node, format.list_block)) {
  13309. each$e(from(node.childNodes), node => {
  13310. if (isValid(ed, forcedRootBlock, node.nodeName.toLowerCase())) {
  13311. if (!rootBlockElm) {
  13312. rootBlockElm = wrap$1(dom, node, forcedRootBlock);
  13313. dom.setAttribs(rootBlockElm, getForcedRootBlockAttrs(ed));
  13314. } else {
  13315. rootBlockElm.appendChild(node);
  13316. }
  13317. } else {
  13318. rootBlockElm = null;
  13319. }
  13320. });
  13321. }
  13322. }
  13323. }
  13324. if (isMixedFormat(format) && !isEq$2(format.inline, node)) {
  13325. return;
  13326. }
  13327. dom.remove(node, true);
  13328. };
  13329. const processFormatAttrOrStyle = (name, value, vars) => {
  13330. if (isNumber(name)) {
  13331. return {
  13332. name: value,
  13333. value: null
  13334. };
  13335. } else {
  13336. return {
  13337. name,
  13338. value: replaceVars(value, vars)
  13339. };
  13340. }
  13341. };
  13342. const removeEmptyStyleAttributeIfNeeded = (dom, elm) => {
  13343. if (dom.getAttrib(elm, 'style') === '') {
  13344. elm.removeAttribute('style');
  13345. elm.removeAttribute('data-mce-style');
  13346. }
  13347. };
  13348. const removeStyles = (dom, elm, format, vars, compareNode) => {
  13349. let stylesModified = false;
  13350. each$7(format.styles, (value, name) => {
  13351. const {
  13352. name: styleName,
  13353. value: styleValue
  13354. } = processFormatAttrOrStyle(name, value, vars);
  13355. const normalizedStyleValue = normalizeStyleValue(styleValue, styleName);
  13356. if (format.remove_similar || isNull(styleValue) || !isElement$6(compareNode) || isEq$2(getStyle(dom, compareNode, styleName), normalizedStyleValue)) {
  13357. dom.setStyle(elm, styleName, '');
  13358. }
  13359. stylesModified = true;
  13360. });
  13361. if (stylesModified) {
  13362. removeEmptyStyleAttributeIfNeeded(dom, elm);
  13363. }
  13364. };
  13365. const removeListStyleFormats = (editor, name, vars) => {
  13366. if (name === 'removeformat') {
  13367. each$e(getPartiallySelectedListItems(editor.selection), li => {
  13368. each$e(listItemStyles, name => editor.dom.setStyle(li, name, ''));
  13369. removeEmptyStyleAttributeIfNeeded(editor.dom, li);
  13370. });
  13371. } else {
  13372. getExpandedListItemFormat(editor.formatter, name).each(liFmt => {
  13373. each$e(getPartiallySelectedListItems(editor.selection), li => removeStyles(editor.dom, li, liFmt, vars, null));
  13374. });
  13375. }
  13376. };
  13377. const removeFormatInternal = (ed, format, vars, node, compareNode) => {
  13378. const dom = ed.dom;
  13379. const elementUtils = ElementUtils(ed);
  13380. const schema = ed.schema;
  13381. if (isInlineFormat(format) && isTransparentElementName(schema, format.inline) && isTransparentBlock(schema, node) && node.parentElement === ed.getBody()) {
  13382. removeNode(ed, node, format);
  13383. return removeResult.removed();
  13384. }
  13385. if (!format.ceFalseOverride && node && dom.getContentEditableParent(node) === 'false') {
  13386. return removeResult.keep();
  13387. }
  13388. if (node && !matchName(dom, node, format) && !isColorFormatAndAnchor(node, format)) {
  13389. return removeResult.keep();
  13390. }
  13391. const elm = node;
  13392. const preserveAttributes = format.preserve_attributes;
  13393. if (isInlineFormat(format) && format.remove === 'all' && isArray$1(preserveAttributes)) {
  13394. const attrsToPreserve = filter$5(dom.getAttribs(elm), attr => contains$2(preserveAttributes, attr.name.toLowerCase()));
  13395. dom.removeAllAttribs(elm);
  13396. each$e(attrsToPreserve, attr => dom.setAttrib(elm, attr.name, attr.value));
  13397. if (attrsToPreserve.length > 0) {
  13398. return removeResult.rename('span');
  13399. }
  13400. }
  13401. if (format.remove !== 'all') {
  13402. removeStyles(dom, elm, format, vars, compareNode);
  13403. each$7(format.attributes, (value, name) => {
  13404. const {
  13405. name: attrName,
  13406. value: attrValue
  13407. } = processFormatAttrOrStyle(name, value, vars);
  13408. if (format.remove_similar || isNull(attrValue) || !isElement$6(compareNode) || isEq$2(dom.getAttrib(compareNode, attrName), attrValue)) {
  13409. if (attrName === 'class') {
  13410. const currentValue = dom.getAttrib(elm, attrName);
  13411. if (currentValue) {
  13412. let valueOut = '';
  13413. each$e(currentValue.split(/\s+/), cls => {
  13414. if (/mce\-\w+/.test(cls)) {
  13415. valueOut += (valueOut ? ' ' : '') + cls;
  13416. }
  13417. });
  13418. if (valueOut) {
  13419. dom.setAttrib(elm, attrName, valueOut);
  13420. return;
  13421. }
  13422. }
  13423. }
  13424. if (MCE_ATTR_RE.test(attrName)) {
  13425. elm.removeAttribute('data-mce-' + attrName);
  13426. }
  13427. if (attrName === 'style' && matchNodeNames(['li'])(elm) && dom.getStyle(elm, 'list-style-type') === 'none') {
  13428. elm.removeAttribute(attrName);
  13429. dom.setStyle(elm, 'list-style-type', 'none');
  13430. return;
  13431. }
  13432. if (attrName === 'class') {
  13433. elm.removeAttribute('className');
  13434. }
  13435. elm.removeAttribute(attrName);
  13436. }
  13437. });
  13438. each$7(format.classes, value => {
  13439. value = replaceVars(value, vars);
  13440. if (!isElement$6(compareNode) || dom.hasClass(compareNode, value)) {
  13441. dom.removeClass(elm, value);
  13442. }
  13443. });
  13444. const attrs = dom.getAttribs(elm);
  13445. for (let i = 0; i < attrs.length; i++) {
  13446. const attrName = attrs[i].nodeName;
  13447. if (!elementUtils.isAttributeInternal(attrName)) {
  13448. return removeResult.keep();
  13449. }
  13450. }
  13451. }
  13452. if (format.remove !== 'none') {
  13453. removeNode(ed, elm, format);
  13454. return removeResult.removed();
  13455. }
  13456. return removeResult.keep();
  13457. };
  13458. const removeFormat$1 = (ed, format, vars, node, compareNode) => removeFormatInternal(ed, format, vars, node, compareNode).fold(never, newName => {
  13459. ed.dom.rename(node, newName);
  13460. return true;
  13461. }, always);
  13462. const findFormatRoot = (editor, container, name, vars, similar) => {
  13463. let formatRoot;
  13464. if (container.parentNode) {
  13465. each$e(getParents$2(editor.dom, container.parentNode).reverse(), parent => {
  13466. if (!formatRoot && isElement$6(parent) && parent.id !== '_start' && parent.id !== '_end') {
  13467. const format = matchNode(editor, parent, name, vars, similar);
  13468. if (format && format.split !== false) {
  13469. formatRoot = parent;
  13470. }
  13471. }
  13472. });
  13473. }
  13474. return formatRoot;
  13475. };
  13476. const removeFormatFromClone = (editor, format, vars, clone) => removeFormatInternal(editor, format, vars, clone, clone).fold(constant(clone), newName => {
  13477. const fragment = editor.dom.createFragment();
  13478. fragment.appendChild(clone);
  13479. return editor.dom.rename(clone, newName);
  13480. }, constant(null));
  13481. const wrapAndSplit = (editor, formatList, formatRoot, container, target, split, format, vars) => {
  13482. var _a, _b;
  13483. let lastClone;
  13484. let firstClone;
  13485. const dom = editor.dom;
  13486. if (formatRoot) {
  13487. const formatRootParent = formatRoot.parentNode;
  13488. for (let parent = container.parentNode; parent && parent !== formatRootParent; parent = parent.parentNode) {
  13489. let clone = dom.clone(parent, false);
  13490. for (let i = 0; i < formatList.length; i++) {
  13491. clone = removeFormatFromClone(editor, formatList[i], vars, clone);
  13492. if (clone === null) {
  13493. break;
  13494. }
  13495. }
  13496. if (clone) {
  13497. if (lastClone) {
  13498. clone.appendChild(lastClone);
  13499. }
  13500. if (!firstClone) {
  13501. firstClone = clone;
  13502. }
  13503. lastClone = clone;
  13504. }
  13505. }
  13506. if (split && (!format.mixed || !dom.isBlock(formatRoot))) {
  13507. container = (_a = dom.split(formatRoot, container)) !== null && _a !== void 0 ? _a : container;
  13508. }
  13509. if (lastClone && firstClone) {
  13510. (_b = target.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(lastClone, target);
  13511. firstClone.appendChild(target);
  13512. if (isInlineFormat(format)) {
  13513. mergeSiblings(editor, format, vars, lastClone);
  13514. }
  13515. }
  13516. }
  13517. return container;
  13518. };
  13519. const remove$2 = (ed, name, vars, node, similar) => {
  13520. const formatList = ed.formatter.get(name);
  13521. const format = formatList[0];
  13522. const dom = ed.dom;
  13523. const selection = ed.selection;
  13524. const splitToFormatRoot = container => {
  13525. const formatRoot = findFormatRoot(ed, container, name, vars, similar);
  13526. return wrapAndSplit(ed, formatList, formatRoot, container, container, true, format, vars);
  13527. };
  13528. const isRemoveBookmarkNode = node => isBookmarkNode$1(node) && isElement$6(node) && (node.id === '_start' || node.id === '_end');
  13529. const removeNodeFormat = node => exists(formatList, fmt => removeFormat$1(ed, fmt, vars, node, node));
  13530. const process = node => {
  13531. const children = from(node.childNodes);
  13532. const removed = removeNodeFormat(node);
  13533. const currentNodeMatches = removed || exists(formatList, f => matchName(dom, node, f));
  13534. const parentNode = node.parentNode;
  13535. if (!currentNodeMatches && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
  13536. removeNodeFormat(parentNode);
  13537. }
  13538. if (format.deep) {
  13539. if (children.length) {
  13540. for (let i = 0; i < children.length; i++) {
  13541. process(children[i]);
  13542. }
  13543. }
  13544. }
  13545. const textDecorations = [
  13546. 'underline',
  13547. 'line-through',
  13548. 'overline'
  13549. ];
  13550. each$e(textDecorations, decoration => {
  13551. if (isElement$6(node) && ed.dom.getStyle(node, 'text-decoration') === decoration && node.parentNode && getTextDecoration(dom, node.parentNode) === decoration) {
  13552. removeFormat$1(ed, {
  13553. deep: false,
  13554. exact: true,
  13555. inline: 'span',
  13556. styles: { textDecoration: decoration }
  13557. }, undefined, node);
  13558. }
  13559. });
  13560. };
  13561. const unwrap = start => {
  13562. const node = dom.get(start ? '_start' : '_end');
  13563. if (node) {
  13564. let out = node[start ? 'firstChild' : 'lastChild'];
  13565. if (isRemoveBookmarkNode(out)) {
  13566. out = out[start ? 'firstChild' : 'lastChild'];
  13567. }
  13568. if (isText$a(out) && out.data.length === 0) {
  13569. out = start ? node.previousSibling || node.nextSibling : node.nextSibling || node.previousSibling;
  13570. }
  13571. dom.remove(node, true);
  13572. return out;
  13573. } else {
  13574. return null;
  13575. }
  13576. };
  13577. const removeRngStyle = rng => {
  13578. let startContainer;
  13579. let endContainer;
  13580. let expandedRng = expandRng(dom, rng, formatList, rng.collapsed);
  13581. if (format.split) {
  13582. expandedRng = split(expandedRng);
  13583. startContainer = getContainer(ed, expandedRng, true);
  13584. endContainer = getContainer(ed, expandedRng);
  13585. if (startContainer !== endContainer) {
  13586. startContainer = normalizeTableSelection(startContainer, true);
  13587. endContainer = normalizeTableSelection(endContainer, false);
  13588. if (isChildOfInlineParent(dom, startContainer, endContainer)) {
  13589. const marker = Optional.from(startContainer.firstChild).getOr(startContainer);
  13590. splitToFormatRoot(wrapWithSiblings(dom, marker, true, 'span', {
  13591. 'id': '_start',
  13592. 'data-mce-type': 'bookmark'
  13593. }));
  13594. unwrap(true);
  13595. return;
  13596. }
  13597. if (isChildOfInlineParent(dom, endContainer, startContainer)) {
  13598. const marker = Optional.from(endContainer.lastChild).getOr(endContainer);
  13599. splitToFormatRoot(wrapWithSiblings(dom, marker, false, 'span', {
  13600. 'id': '_end',
  13601. 'data-mce-type': 'bookmark'
  13602. }));
  13603. unwrap(false);
  13604. return;
  13605. }
  13606. startContainer = wrap$1(dom, startContainer, 'span', {
  13607. 'id': '_start',
  13608. 'data-mce-type': 'bookmark'
  13609. });
  13610. endContainer = wrap$1(dom, endContainer, 'span', {
  13611. 'id': '_end',
  13612. 'data-mce-type': 'bookmark'
  13613. });
  13614. const newRng = dom.createRng();
  13615. newRng.setStartAfter(startContainer);
  13616. newRng.setEndBefore(endContainer);
  13617. walk$3(dom, newRng, nodes => {
  13618. each$e(nodes, n => {
  13619. if (!isBookmarkNode$1(n) && !isBookmarkNode$1(n.parentNode)) {
  13620. splitToFormatRoot(n);
  13621. }
  13622. });
  13623. });
  13624. splitToFormatRoot(startContainer);
  13625. splitToFormatRoot(endContainer);
  13626. startContainer = unwrap(true);
  13627. endContainer = unwrap();
  13628. } else {
  13629. startContainer = endContainer = splitToFormatRoot(startContainer);
  13630. }
  13631. expandedRng.startContainer = startContainer.parentNode ? startContainer.parentNode : startContainer;
  13632. expandedRng.startOffset = dom.nodeIndex(startContainer);
  13633. expandedRng.endContainer = endContainer.parentNode ? endContainer.parentNode : endContainer;
  13634. expandedRng.endOffset = dom.nodeIndex(endContainer) + 1;
  13635. }
  13636. walk$3(dom, expandedRng, nodes => {
  13637. each$e(nodes, process);
  13638. });
  13639. };
  13640. if (node) {
  13641. if (isNode(node)) {
  13642. const rng = dom.createRng();
  13643. rng.setStartBefore(node);
  13644. rng.setEndAfter(node);
  13645. removeRngStyle(rng);
  13646. } else {
  13647. removeRngStyle(node);
  13648. }
  13649. fireFormatRemove(ed, name, node, vars);
  13650. return;
  13651. }
  13652. if (!selection.isCollapsed() || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
  13653. preserveSelection(ed, () => runOnRanges(ed, removeRngStyle), startNode => isInlineFormat(format) && match$2(ed, name, vars, startNode));
  13654. ed.nodeChanged();
  13655. } else {
  13656. removeCaretFormat(ed, name, vars, similar);
  13657. }
  13658. removeListStyleFormats(ed, name, vars);
  13659. fireFormatRemove(ed, name, node, vars);
  13660. };
  13661. const each$6 = Tools.each;
  13662. const mergeTextDecorationsAndColor = (dom, format, vars, node) => {
  13663. const processTextDecorationsAndColor = n => {
  13664. if (isElement$6(n) && isElement$6(n.parentNode) && isEditable$3(n)) {
  13665. const parentTextDecoration = getTextDecoration(dom, n.parentNode);
  13666. if (dom.getStyle(n, 'color') && parentTextDecoration) {
  13667. dom.setStyle(n, 'text-decoration', parentTextDecoration);
  13668. } else if (dom.getStyle(n, 'text-decoration') === parentTextDecoration) {
  13669. dom.setStyle(n, 'text-decoration', null);
  13670. }
  13671. }
  13672. };
  13673. if (format.styles && (format.styles.color || format.styles.textDecoration)) {
  13674. Tools.walk(node, processTextDecorationsAndColor, 'childNodes');
  13675. processTextDecorationsAndColor(node);
  13676. }
  13677. };
  13678. const mergeBackgroundColorAndFontSize = (dom, format, vars, node) => {
  13679. if (format.styles && format.styles.backgroundColor) {
  13680. const hasFontSize = hasStyle(dom, 'fontSize');
  13681. processChildElements(node, elm => hasFontSize(elm) && isEditable$3(elm), applyStyle(dom, 'backgroundColor', replaceVars(format.styles.backgroundColor, vars)));
  13682. }
  13683. };
  13684. const mergeSubSup = (dom, format, vars, node) => {
  13685. if (isInlineFormat(format) && (format.inline === 'sub' || format.inline === 'sup')) {
  13686. const hasFontSize = hasStyle(dom, 'fontSize');
  13687. processChildElements(node, elm => hasFontSize(elm) && isEditable$3(elm), applyStyle(dom, 'fontSize', ''));
  13688. const inverseTagDescendants = filter$5(dom.select(format.inline === 'sup' ? 'sub' : 'sup', node), isEditable$3);
  13689. dom.remove(inverseTagDescendants, true);
  13690. }
  13691. };
  13692. const mergeWithChildren = (editor, formatList, vars, node) => {
  13693. each$6(formatList, format => {
  13694. if (isInlineFormat(format)) {
  13695. each$6(editor.dom.select(format.inline, node), child => {
  13696. if (isElementNode(child)) {
  13697. removeFormat$1(editor, format, vars, child, format.exact ? child : null);
  13698. }
  13699. });
  13700. }
  13701. clearChildStyles(editor.dom, format, node);
  13702. });
  13703. };
  13704. const mergeWithParents = (editor, format, name, vars, node) => {
  13705. const parentNode = node.parentNode;
  13706. if (matchNode(editor, parentNode, name, vars)) {
  13707. if (removeFormat$1(editor, format, vars, node)) {
  13708. return;
  13709. }
  13710. }
  13711. if (format.merge_with_parents && parentNode) {
  13712. editor.dom.getParent(parentNode, parent => {
  13713. if (matchNode(editor, parent, name, vars)) {
  13714. removeFormat$1(editor, format, vars, node);
  13715. return true;
  13716. } else {
  13717. return false;
  13718. }
  13719. });
  13720. }
  13721. };
  13722. const each$5 = Tools.each;
  13723. const canFormatBR = (editor, format, node, parentName) => {
  13724. if (canFormatEmptyLines(editor) && isInlineFormat(format) && node.parentNode) {
  13725. const validBRParentElements = getTextRootBlockElements(editor.schema);
  13726. const hasCaretNodeSibling = sibling(SugarElement.fromDom(node), sibling => isCaretNode(sibling.dom));
  13727. return hasNonNullableKey(validBRParentElements, parentName) && isEmpty$2(SugarElement.fromDom(node.parentNode), false) && !hasCaretNodeSibling;
  13728. } else {
  13729. return false;
  13730. }
  13731. };
  13732. const applyStyles = (dom, elm, format, vars) => {
  13733. each$5(format.styles, (value, name) => {
  13734. dom.setStyle(elm, name, replaceVars(value, vars));
  13735. });
  13736. if (format.styles) {
  13737. const styleVal = dom.getAttrib(elm, 'style');
  13738. if (styleVal) {
  13739. dom.setAttrib(elm, 'data-mce-style', styleVal);
  13740. }
  13741. }
  13742. };
  13743. const applyFormat$1 = (ed, name, vars, node) => {
  13744. const formatList = ed.formatter.get(name);
  13745. const format = formatList[0];
  13746. const isCollapsed = !node && ed.selection.isCollapsed();
  13747. const dom = ed.dom;
  13748. const selection = ed.selection;
  13749. const setElementFormat = (elm, fmt = format) => {
  13750. if (isFunction(fmt.onformat)) {
  13751. fmt.onformat(elm, fmt, vars, node);
  13752. }
  13753. applyStyles(dom, elm, fmt, vars);
  13754. each$5(fmt.attributes, (value, name) => {
  13755. dom.setAttrib(elm, name, replaceVars(value, vars));
  13756. });
  13757. each$5(fmt.classes, value => {
  13758. const newValue = replaceVars(value, vars);
  13759. if (!dom.hasClass(elm, newValue)) {
  13760. dom.addClass(elm, newValue);
  13761. }
  13762. });
  13763. };
  13764. const applyNodeStyle = (formatList, node) => {
  13765. let found = false;
  13766. each$5(formatList, format => {
  13767. if (!isSelectorFormat(format)) {
  13768. return false;
  13769. }
  13770. if (dom.getContentEditable(node) === 'false' && !format.ceFalseOverride) {
  13771. return true;
  13772. }
  13773. if (isNonNullable(format.collapsed) && format.collapsed !== isCollapsed) {
  13774. return true;
  13775. }
  13776. if (dom.is(node, format.selector) && !isCaretNode(node)) {
  13777. setElementFormat(node, format);
  13778. found = true;
  13779. return false;
  13780. }
  13781. return true;
  13782. });
  13783. return found;
  13784. };
  13785. const createWrapElement = wrapName => {
  13786. if (isString(wrapName)) {
  13787. const wrapElm = dom.create(wrapName);
  13788. setElementFormat(wrapElm);
  13789. return wrapElm;
  13790. } else {
  13791. return null;
  13792. }
  13793. };
  13794. const applyRngStyle = (dom, rng, nodeSpecific) => {
  13795. const newWrappers = [];
  13796. let contentEditable = true;
  13797. const wrapName = format.inline || format.block;
  13798. const wrapElm = createWrapElement(wrapName);
  13799. const isMatchingWrappingBlock = node => isWrappingBlockFormat(format) && matchNode(ed, node, name, vars);
  13800. const canRenameBlock = (node, parentName, isEditableDescendant) => {
  13801. const isValidBlockFormatForNode = isNonWrappingBlockFormat(format) && isTextBlock$1(ed.schema, node) && isValid(ed, parentName, wrapName);
  13802. return isEditableDescendant && isValidBlockFormatForNode;
  13803. };
  13804. const canWrapNode = (node, parentName, isEditableDescendant, isWrappableNoneditableElm) => {
  13805. const nodeName = node.nodeName.toLowerCase();
  13806. const isValidWrapNode = isValid(ed, wrapName, nodeName) && isValid(ed, parentName, wrapName);
  13807. const isZwsp$1 = !nodeSpecific && isText$a(node) && isZwsp(node.data);
  13808. const isCaret = isCaretNode(node);
  13809. const isCorrectFormatForNode = !isInlineFormat(format) || !dom.isBlock(node);
  13810. return (isEditableDescendant || isWrappableNoneditableElm) && isValidWrapNode && !isZwsp$1 && !isCaret && isCorrectFormatForNode;
  13811. };
  13812. walk$3(dom, rng, nodes => {
  13813. let currentWrapElm;
  13814. const process = node => {
  13815. let hasContentEditableState = false;
  13816. let lastContentEditable = contentEditable;
  13817. let isWrappableNoneditableElm = false;
  13818. const parentNode = node.parentNode;
  13819. const parentName = parentNode.nodeName.toLowerCase();
  13820. const contentEditableValue = dom.getContentEditable(node);
  13821. if (isNonNullable(contentEditableValue)) {
  13822. lastContentEditable = contentEditable;
  13823. contentEditable = contentEditableValue === 'true';
  13824. hasContentEditableState = true;
  13825. isWrappableNoneditableElm = isWrappableNoneditable(ed, node);
  13826. }
  13827. const isEditableDescendant = contentEditable && !hasContentEditableState;
  13828. if (isBr$6(node) && !canFormatBR(ed, format, node, parentName)) {
  13829. currentWrapElm = null;
  13830. if (isBlockFormat(format)) {
  13831. dom.remove(node);
  13832. }
  13833. return;
  13834. }
  13835. if (isMatchingWrappingBlock(node)) {
  13836. currentWrapElm = null;
  13837. return;
  13838. }
  13839. if (canRenameBlock(node, parentName, isEditableDescendant)) {
  13840. const elm = dom.rename(node, wrapName);
  13841. setElementFormat(elm);
  13842. newWrappers.push(elm);
  13843. currentWrapElm = null;
  13844. return;
  13845. }
  13846. if (isSelectorFormat(format)) {
  13847. let found = applyNodeStyle(formatList, node);
  13848. if (!found && isNonNullable(parentNode) && shouldExpandToSelector(format)) {
  13849. found = applyNodeStyle(formatList, parentNode);
  13850. }
  13851. if (!isInlineFormat(format) || found) {
  13852. currentWrapElm = null;
  13853. return;
  13854. }
  13855. }
  13856. if (isNonNullable(wrapElm) && canWrapNode(node, parentName, isEditableDescendant, isWrappableNoneditableElm)) {
  13857. if (!currentWrapElm) {
  13858. currentWrapElm = dom.clone(wrapElm, false);
  13859. parentNode.insertBefore(currentWrapElm, node);
  13860. newWrappers.push(currentWrapElm);
  13861. }
  13862. if (isWrappableNoneditableElm && hasContentEditableState) {
  13863. contentEditable = lastContentEditable;
  13864. }
  13865. currentWrapElm.appendChild(node);
  13866. } else {
  13867. currentWrapElm = null;
  13868. each$e(from(node.childNodes), process);
  13869. if (hasContentEditableState) {
  13870. contentEditable = lastContentEditable;
  13871. }
  13872. currentWrapElm = null;
  13873. }
  13874. };
  13875. each$e(nodes, process);
  13876. });
  13877. if (format.links === true) {
  13878. each$e(newWrappers, node => {
  13879. const process = node => {
  13880. if (node.nodeName === 'A') {
  13881. setElementFormat(node, format);
  13882. }
  13883. each$e(from(node.childNodes), process);
  13884. };
  13885. process(node);
  13886. });
  13887. }
  13888. each$e(newWrappers, node => {
  13889. const getChildCount = node => {
  13890. let count = 0;
  13891. each$e(node.childNodes, node => {
  13892. if (!isEmptyTextNode$1(node) && !isBookmarkNode$1(node)) {
  13893. count++;
  13894. }
  13895. });
  13896. return count;
  13897. };
  13898. const mergeStyles = node => {
  13899. const childElement = find$2(node.childNodes, isElementNode$1).filter(child => dom.getContentEditable(child) !== 'false' && matchName(dom, child, format));
  13900. return childElement.map(child => {
  13901. const clone = dom.clone(child, false);
  13902. setElementFormat(clone);
  13903. dom.replace(clone, node, true);
  13904. dom.remove(child, true);
  13905. return clone;
  13906. }).getOr(node);
  13907. };
  13908. const childCount = getChildCount(node);
  13909. if ((newWrappers.length > 1 || !dom.isBlock(node)) && childCount === 0) {
  13910. dom.remove(node, true);
  13911. return;
  13912. }
  13913. if (isInlineFormat(format) || isBlockFormat(format) && format.wrapper) {
  13914. if (!format.exact && childCount === 1) {
  13915. node = mergeStyles(node);
  13916. }
  13917. mergeWithChildren(ed, formatList, vars, node);
  13918. mergeWithParents(ed, format, name, vars, node);
  13919. mergeBackgroundColorAndFontSize(dom, format, vars, node);
  13920. mergeTextDecorationsAndColor(dom, format, vars, node);
  13921. mergeSubSup(dom, format, vars, node);
  13922. mergeSiblings(ed, format, vars, node);
  13923. }
  13924. });
  13925. };
  13926. const targetNode = isNode(node) ? node : selection.getNode();
  13927. if (dom.getContentEditable(targetNode) === 'false' && !isWrappableNoneditable(ed, targetNode)) {
  13928. node = targetNode;
  13929. applyNodeStyle(formatList, node);
  13930. fireFormatApply(ed, name, node, vars);
  13931. return;
  13932. }
  13933. if (format) {
  13934. if (node) {
  13935. if (isNode(node)) {
  13936. if (!applyNodeStyle(formatList, node)) {
  13937. const rng = dom.createRng();
  13938. rng.setStartBefore(node);
  13939. rng.setEndAfter(node);
  13940. applyRngStyle(dom, expandRng(dom, rng, formatList), true);
  13941. }
  13942. } else {
  13943. applyRngStyle(dom, node, true);
  13944. }
  13945. } else {
  13946. if (!isCollapsed || !isInlineFormat(format) || getCellsFromEditor(ed).length) {
  13947. selection.setRng(normalize(selection.getRng()));
  13948. preserveSelection(ed, () => {
  13949. runOnRanges(ed, (selectionRng, fake) => {
  13950. const expandedRng = fake ? selectionRng : expandRng(dom, selectionRng, formatList);
  13951. applyRngStyle(dom, expandedRng, false);
  13952. });
  13953. }, always);
  13954. ed.nodeChanged();
  13955. } else {
  13956. applyCaretFormat(ed, name, vars);
  13957. }
  13958. getExpandedListItemFormat(ed.formatter, name).each(liFmt => {
  13959. each$e(getFullySelectedListItems(ed.selection), li => applyStyles(dom, li, liFmt, vars));
  13960. });
  13961. }
  13962. postProcess$1(name, ed);
  13963. }
  13964. fireFormatApply(ed, name, node, vars);
  13965. };
  13966. const hasVars = value => has$2(value, 'vars');
  13967. const setup$t = (registeredFormatListeners, editor) => {
  13968. registeredFormatListeners.set({});
  13969. editor.on('NodeChange', e => {
  13970. updateAndFireChangeCallbacks(editor, e.element, registeredFormatListeners.get());
  13971. });
  13972. editor.on('FormatApply FormatRemove', e => {
  13973. const element = Optional.from(e.node).map(nodeOrRange => isNode(nodeOrRange) ? nodeOrRange : nodeOrRange.startContainer).bind(node => isElement$6(node) ? Optional.some(node) : Optional.from(node.parentElement)).getOrThunk(() => fallbackElement(editor));
  13974. updateAndFireChangeCallbacks(editor, element, registeredFormatListeners.get());
  13975. });
  13976. };
  13977. const fallbackElement = editor => editor.selection.getStart();
  13978. const matchingNode = (editor, parents, format, similar, vars) => {
  13979. const isMatchingNode = node => {
  13980. const matchingFormat = editor.formatter.matchNode(node, format, vars !== null && vars !== void 0 ? vars : {}, similar);
  13981. return !isUndefined(matchingFormat);
  13982. };
  13983. const isUnableToMatch = node => {
  13984. if (matchesUnInheritedFormatSelector(editor, node, format)) {
  13985. return true;
  13986. } else {
  13987. if (!similar) {
  13988. return isNonNullable(editor.formatter.matchNode(node, format, vars, true));
  13989. } else {
  13990. return false;
  13991. }
  13992. }
  13993. };
  13994. return findUntil$1(parents, isMatchingNode, isUnableToMatch);
  13995. };
  13996. const getParents = (editor, elm) => {
  13997. const element = elm !== null && elm !== void 0 ? elm : fallbackElement(editor);
  13998. return filter$5(getParents$2(editor.dom, element), node => isElement$6(node) && !isBogus$2(node));
  13999. };
  14000. const updateAndFireChangeCallbacks = (editor, elm, registeredCallbacks) => {
  14001. const parents = getParents(editor, elm);
  14002. each$d(registeredCallbacks, (data, format) => {
  14003. const runIfChanged = spec => {
  14004. const match = matchingNode(editor, parents, format, spec.similar, hasVars(spec) ? spec.vars : undefined);
  14005. const isSet = match.isSome();
  14006. if (spec.state.get() !== isSet) {
  14007. spec.state.set(isSet);
  14008. const node = match.getOr(elm);
  14009. if (hasVars(spec)) {
  14010. spec.callback(isSet, {
  14011. node,
  14012. format,
  14013. parents
  14014. });
  14015. } else {
  14016. each$e(spec.callbacks, callback => callback(isSet, {
  14017. node,
  14018. format,
  14019. parents
  14020. }));
  14021. }
  14022. }
  14023. };
  14024. each$e([
  14025. data.withSimilar,
  14026. data.withoutSimilar
  14027. ], runIfChanged);
  14028. each$e(data.withVars, runIfChanged);
  14029. });
  14030. };
  14031. const addListeners = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
  14032. const formatChangeItems = registeredFormatListeners.get();
  14033. each$e(formats.split(','), format => {
  14034. const group = get$a(formatChangeItems, format).getOrThunk(() => {
  14035. const base = {
  14036. withSimilar: {
  14037. state: Cell(false),
  14038. similar: true,
  14039. callbacks: []
  14040. },
  14041. withoutSimilar: {
  14042. state: Cell(false),
  14043. similar: false,
  14044. callbacks: []
  14045. },
  14046. withVars: []
  14047. };
  14048. formatChangeItems[format] = base;
  14049. return base;
  14050. });
  14051. const getCurrent = () => {
  14052. const parents = getParents(editor);
  14053. return matchingNode(editor, parents, format, similar, vars).isSome();
  14054. };
  14055. if (isUndefined(vars)) {
  14056. const toAppendTo = similar ? group.withSimilar : group.withoutSimilar;
  14057. toAppendTo.callbacks.push(callback);
  14058. if (toAppendTo.callbacks.length === 1) {
  14059. toAppendTo.state.set(getCurrent());
  14060. }
  14061. } else {
  14062. group.withVars.push({
  14063. state: Cell(getCurrent()),
  14064. similar,
  14065. vars,
  14066. callback
  14067. });
  14068. }
  14069. });
  14070. registeredFormatListeners.set(formatChangeItems);
  14071. };
  14072. const removeListeners = (registeredFormatListeners, formats, callback) => {
  14073. const formatChangeItems = registeredFormatListeners.get();
  14074. each$e(formats.split(','), format => get$a(formatChangeItems, format).each(group => {
  14075. formatChangeItems[format] = {
  14076. withSimilar: {
  14077. ...group.withSimilar,
  14078. callbacks: filter$5(group.withSimilar.callbacks, cb => cb !== callback)
  14079. },
  14080. withoutSimilar: {
  14081. ...group.withoutSimilar,
  14082. callbacks: filter$5(group.withoutSimilar.callbacks, cb => cb !== callback)
  14083. },
  14084. withVars: filter$5(group.withVars, item => item.callback !== callback)
  14085. };
  14086. }));
  14087. registeredFormatListeners.set(formatChangeItems);
  14088. };
  14089. const formatChangedInternal = (editor, registeredFormatListeners, formats, callback, similar, vars) => {
  14090. addListeners(editor, registeredFormatListeners, formats, callback, similar, vars);
  14091. return { unbind: () => removeListeners(registeredFormatListeners, formats, callback) };
  14092. };
  14093. const toggle = (editor, name, vars, node) => {
  14094. const fmt = editor.formatter.get(name);
  14095. if (fmt) {
  14096. if (match$2(editor, name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle)) {
  14097. remove$2(editor, name, vars, node);
  14098. } else {
  14099. applyFormat$1(editor, name, vars, node);
  14100. }
  14101. }
  14102. };
  14103. function _typeof(obj) {
  14104. '@babel/helpers - typeof';
  14105. return _typeof = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (obj) {
  14106. return typeof obj;
  14107. } : function (obj) {
  14108. return obj && 'function' == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? 'symbol' : typeof obj;
  14109. }, _typeof(obj);
  14110. }
  14111. function _setPrototypeOf(o, p) {
  14112. _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
  14113. o.__proto__ = p;
  14114. return o;
  14115. };
  14116. return _setPrototypeOf(o, p);
  14117. }
  14118. function _isNativeReflectConstruct() {
  14119. if (typeof Reflect === 'undefined' || !Reflect.construct)
  14120. return false;
  14121. if (Reflect.construct.sham)
  14122. return false;
  14123. if (typeof Proxy === 'function')
  14124. return true;
  14125. try {
  14126. Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {
  14127. }));
  14128. return true;
  14129. } catch (e) {
  14130. return false;
  14131. }
  14132. }
  14133. function _construct(Parent, args, Class) {
  14134. if (_isNativeReflectConstruct()) {
  14135. _construct = Reflect.construct;
  14136. } else {
  14137. _construct = function _construct(Parent, args, Class) {
  14138. var a = [null];
  14139. a.push.apply(a, args);
  14140. var Constructor = Function.bind.apply(Parent, a);
  14141. var instance = new Constructor();
  14142. if (Class)
  14143. _setPrototypeOf(instance, Class.prototype);
  14144. return instance;
  14145. };
  14146. }
  14147. return _construct.apply(null, arguments);
  14148. }
  14149. function _toConsumableArray(arr) {
  14150. return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  14151. }
  14152. function _arrayWithoutHoles(arr) {
  14153. if (Array.isArray(arr))
  14154. return _arrayLikeToArray(arr);
  14155. }
  14156. function _iterableToArray(iter) {
  14157. if (typeof Symbol !== 'undefined' && iter[Symbol.iterator] != null || iter['@@iterator'] != null)
  14158. return Array.from(iter);
  14159. }
  14160. function _unsupportedIterableToArray(o, minLen) {
  14161. if (!o)
  14162. return;
  14163. if (typeof o === 'string')
  14164. return _arrayLikeToArray(o, minLen);
  14165. var n = Object.prototype.toString.call(o).slice(8, -1);
  14166. if (n === 'Object' && o.constructor)
  14167. n = o.constructor.name;
  14168. if (n === 'Map' || n === 'Set')
  14169. return Array.from(o);
  14170. if (n === 'Arguments' || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))
  14171. return _arrayLikeToArray(o, minLen);
  14172. }
  14173. function _arrayLikeToArray(arr, len) {
  14174. if (len == null || len > arr.length)
  14175. len = arr.length;
  14176. for (var i = 0, arr2 = new Array(len); i < len; i++)
  14177. arr2[i] = arr[i];
  14178. return arr2;
  14179. }
  14180. function _nonIterableSpread() {
  14181. throw new TypeError('Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.');
  14182. }
  14183. var hasOwnProperty = Object.hasOwnProperty, setPrototypeOf = Object.setPrototypeOf, isFrozen = Object.isFrozen, getPrototypeOf = Object.getPrototypeOf, getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
  14184. var freeze = Object.freeze, seal = Object.seal, create$8 = Object.create;
  14185. var _ref = typeof Reflect !== 'undefined' && Reflect, apply = _ref.apply, construct = _ref.construct;
  14186. if (!apply) {
  14187. apply = function apply(fun, thisValue, args) {
  14188. return fun.apply(thisValue, args);
  14189. };
  14190. }
  14191. if (!freeze) {
  14192. freeze = function freeze(x) {
  14193. return x;
  14194. };
  14195. }
  14196. if (!seal) {
  14197. seal = function seal(x) {
  14198. return x;
  14199. };
  14200. }
  14201. if (!construct) {
  14202. construct = function construct(Func, args) {
  14203. return _construct(Func, _toConsumableArray(args));
  14204. };
  14205. }
  14206. var arrayForEach = unapply(Array.prototype.forEach);
  14207. var arrayPop = unapply(Array.prototype.pop);
  14208. var arrayPush = unapply(Array.prototype.push);
  14209. var stringToLowerCase = unapply(String.prototype.toLowerCase);
  14210. var stringMatch = unapply(String.prototype.match);
  14211. var stringReplace = unapply(String.prototype.replace);
  14212. var stringIndexOf = unapply(String.prototype.indexOf);
  14213. var stringTrim = unapply(String.prototype.trim);
  14214. var regExpTest = unapply(RegExp.prototype.test);
  14215. var typeErrorCreate = unconstruct(TypeError);
  14216. function unapply(func) {
  14217. return function (thisArg) {
  14218. for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  14219. args[_key - 1] = arguments[_key];
  14220. }
  14221. return apply(func, thisArg, args);
  14222. };
  14223. }
  14224. function unconstruct(func) {
  14225. return function () {
  14226. for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
  14227. args[_key2] = arguments[_key2];
  14228. }
  14229. return construct(func, args);
  14230. };
  14231. }
  14232. function addToSet(set, array) {
  14233. if (setPrototypeOf) {
  14234. setPrototypeOf(set, null);
  14235. }
  14236. var l = array.length;
  14237. while (l--) {
  14238. var element = array[l];
  14239. if (typeof element === 'string') {
  14240. var lcElement = stringToLowerCase(element);
  14241. if (lcElement !== element) {
  14242. if (!isFrozen(array)) {
  14243. array[l] = lcElement;
  14244. }
  14245. element = lcElement;
  14246. }
  14247. }
  14248. set[element] = true;
  14249. }
  14250. return set;
  14251. }
  14252. function clone(object) {
  14253. var newObject = create$8(null);
  14254. var property;
  14255. for (property in object) {
  14256. if (apply(hasOwnProperty, object, [property])) {
  14257. newObject[property] = object[property];
  14258. }
  14259. }
  14260. return newObject;
  14261. }
  14262. function lookupGetter(object, prop) {
  14263. while (object !== null) {
  14264. var desc = getOwnPropertyDescriptor(object, prop);
  14265. if (desc) {
  14266. if (desc.get) {
  14267. return unapply(desc.get);
  14268. }
  14269. if (typeof desc.value === 'function') {
  14270. return unapply(desc.value);
  14271. }
  14272. }
  14273. object = getPrototypeOf(object);
  14274. }
  14275. function fallbackValue(element) {
  14276. console.warn('fallback value for', element);
  14277. return null;
  14278. }
  14279. return fallbackValue;
  14280. }
  14281. var html$1 = freeze([
  14282. 'a',
  14283. 'abbr',
  14284. 'acronym',
  14285. 'address',
  14286. 'area',
  14287. 'article',
  14288. 'aside',
  14289. 'audio',
  14290. 'b',
  14291. 'bdi',
  14292. 'bdo',
  14293. 'big',
  14294. 'blink',
  14295. 'blockquote',
  14296. 'body',
  14297. 'br',
  14298. 'button',
  14299. 'canvas',
  14300. 'caption',
  14301. 'center',
  14302. 'cite',
  14303. 'code',
  14304. 'col',
  14305. 'colgroup',
  14306. 'content',
  14307. 'data',
  14308. 'datalist',
  14309. 'dd',
  14310. 'decorator',
  14311. 'del',
  14312. 'details',
  14313. 'dfn',
  14314. 'dialog',
  14315. 'dir',
  14316. 'div',
  14317. 'dl',
  14318. 'dt',
  14319. 'element',
  14320. 'em',
  14321. 'fieldset',
  14322. 'figcaption',
  14323. 'figure',
  14324. 'font',
  14325. 'footer',
  14326. 'form',
  14327. 'h1',
  14328. 'h2',
  14329. 'h3',
  14330. 'h4',
  14331. 'h5',
  14332. 'h6',
  14333. 'head',
  14334. 'header',
  14335. 'hgroup',
  14336. 'hr',
  14337. 'html',
  14338. 'i',
  14339. 'img',
  14340. 'input',
  14341. 'ins',
  14342. 'kbd',
  14343. 'label',
  14344. 'legend',
  14345. 'li',
  14346. 'main',
  14347. 'map',
  14348. 'mark',
  14349. 'marquee',
  14350. 'menu',
  14351. 'menuitem',
  14352. 'meter',
  14353. 'nav',
  14354. 'nobr',
  14355. 'ol',
  14356. 'optgroup',
  14357. 'option',
  14358. 'output',
  14359. 'p',
  14360. 'picture',
  14361. 'pre',
  14362. 'progress',
  14363. 'q',
  14364. 'rp',
  14365. 'rt',
  14366. 'ruby',
  14367. 's',
  14368. 'samp',
  14369. 'section',
  14370. 'select',
  14371. 'shadow',
  14372. 'small',
  14373. 'source',
  14374. 'spacer',
  14375. 'span',
  14376. 'strike',
  14377. 'strong',
  14378. 'style',
  14379. 'sub',
  14380. 'summary',
  14381. 'sup',
  14382. 'table',
  14383. 'tbody',
  14384. 'td',
  14385. 'template',
  14386. 'textarea',
  14387. 'tfoot',
  14388. 'th',
  14389. 'thead',
  14390. 'time',
  14391. 'tr',
  14392. 'track',
  14393. 'tt',
  14394. 'u',
  14395. 'ul',
  14396. 'var',
  14397. 'video',
  14398. 'wbr'
  14399. ]);
  14400. var svg$1 = freeze([
  14401. 'svg',
  14402. 'a',
  14403. 'altglyph',
  14404. 'altglyphdef',
  14405. 'altglyphitem',
  14406. 'animatecolor',
  14407. 'animatemotion',
  14408. 'animatetransform',
  14409. 'circle',
  14410. 'clippath',
  14411. 'defs',
  14412. 'desc',
  14413. 'ellipse',
  14414. 'filter',
  14415. 'font',
  14416. 'g',
  14417. 'glyph',
  14418. 'glyphref',
  14419. 'hkern',
  14420. 'image',
  14421. 'line',
  14422. 'lineargradient',
  14423. 'marker',
  14424. 'mask',
  14425. 'metadata',
  14426. 'mpath',
  14427. 'path',
  14428. 'pattern',
  14429. 'polygon',
  14430. 'polyline',
  14431. 'radialgradient',
  14432. 'rect',
  14433. 'stop',
  14434. 'style',
  14435. 'switch',
  14436. 'symbol',
  14437. 'text',
  14438. 'textpath',
  14439. 'title',
  14440. 'tref',
  14441. 'tspan',
  14442. 'view',
  14443. 'vkern'
  14444. ]);
  14445. var svgFilters = freeze([
  14446. 'feBlend',
  14447. 'feColorMatrix',
  14448. 'feComponentTransfer',
  14449. 'feComposite',
  14450. 'feConvolveMatrix',
  14451. 'feDiffuseLighting',
  14452. 'feDisplacementMap',
  14453. 'feDistantLight',
  14454. 'feFlood',
  14455. 'feFuncA',
  14456. 'feFuncB',
  14457. 'feFuncG',
  14458. 'feFuncR',
  14459. 'feGaussianBlur',
  14460. 'feImage',
  14461. 'feMerge',
  14462. 'feMergeNode',
  14463. 'feMorphology',
  14464. 'feOffset',
  14465. 'fePointLight',
  14466. 'feSpecularLighting',
  14467. 'feSpotLight',
  14468. 'feTile',
  14469. 'feTurbulence'
  14470. ]);
  14471. var svgDisallowed = freeze([
  14472. 'animate',
  14473. 'color-profile',
  14474. 'cursor',
  14475. 'discard',
  14476. 'fedropshadow',
  14477. 'font-face',
  14478. 'font-face-format',
  14479. 'font-face-name',
  14480. 'font-face-src',
  14481. 'font-face-uri',
  14482. 'foreignobject',
  14483. 'hatch',
  14484. 'hatchpath',
  14485. 'mesh',
  14486. 'meshgradient',
  14487. 'meshpatch',
  14488. 'meshrow',
  14489. 'missing-glyph',
  14490. 'script',
  14491. 'set',
  14492. 'solidcolor',
  14493. 'unknown',
  14494. 'use'
  14495. ]);
  14496. var mathMl$1 = freeze([
  14497. 'math',
  14498. 'menclose',
  14499. 'merror',
  14500. 'mfenced',
  14501. 'mfrac',
  14502. 'mglyph',
  14503. 'mi',
  14504. 'mlabeledtr',
  14505. 'mmultiscripts',
  14506. 'mn',
  14507. 'mo',
  14508. 'mover',
  14509. 'mpadded',
  14510. 'mphantom',
  14511. 'mroot',
  14512. 'mrow',
  14513. 'ms',
  14514. 'mspace',
  14515. 'msqrt',
  14516. 'mstyle',
  14517. 'msub',
  14518. 'msup',
  14519. 'msubsup',
  14520. 'mtable',
  14521. 'mtd',
  14522. 'mtext',
  14523. 'mtr',
  14524. 'munder',
  14525. 'munderover'
  14526. ]);
  14527. var mathMlDisallowed = freeze([
  14528. 'maction',
  14529. 'maligngroup',
  14530. 'malignmark',
  14531. 'mlongdiv',
  14532. 'mscarries',
  14533. 'mscarry',
  14534. 'msgroup',
  14535. 'mstack',
  14536. 'msline',
  14537. 'msrow',
  14538. 'semantics',
  14539. 'annotation',
  14540. 'annotation-xml',
  14541. 'mprescripts',
  14542. 'none'
  14543. ]);
  14544. var text = freeze(['#text']);
  14545. var html = freeze([
  14546. 'accept',
  14547. 'action',
  14548. 'align',
  14549. 'alt',
  14550. 'autocapitalize',
  14551. 'autocomplete',
  14552. 'autopictureinpicture',
  14553. 'autoplay',
  14554. 'background',
  14555. 'bgcolor',
  14556. 'border',
  14557. 'capture',
  14558. 'cellpadding',
  14559. 'cellspacing',
  14560. 'checked',
  14561. 'cite',
  14562. 'class',
  14563. 'clear',
  14564. 'color',
  14565. 'cols',
  14566. 'colspan',
  14567. 'controls',
  14568. 'controlslist',
  14569. 'coords',
  14570. 'crossorigin',
  14571. 'datetime',
  14572. 'decoding',
  14573. 'default',
  14574. 'dir',
  14575. 'disabled',
  14576. 'disablepictureinpicture',
  14577. 'disableremoteplayback',
  14578. 'download',
  14579. 'draggable',
  14580. 'enctype',
  14581. 'enterkeyhint',
  14582. 'face',
  14583. 'for',
  14584. 'headers',
  14585. 'height',
  14586. 'hidden',
  14587. 'high',
  14588. 'href',
  14589. 'hreflang',
  14590. 'id',
  14591. 'inputmode',
  14592. 'integrity',
  14593. 'ismap',
  14594. 'kind',
  14595. 'label',
  14596. 'lang',
  14597. 'list',
  14598. 'loading',
  14599. 'loop',
  14600. 'low',
  14601. 'max',
  14602. 'maxlength',
  14603. 'media',
  14604. 'method',
  14605. 'min',
  14606. 'minlength',
  14607. 'multiple',
  14608. 'muted',
  14609. 'name',
  14610. 'nonce',
  14611. 'noshade',
  14612. 'novalidate',
  14613. 'nowrap',
  14614. 'open',
  14615. 'optimum',
  14616. 'pattern',
  14617. 'placeholder',
  14618. 'playsinline',
  14619. 'poster',
  14620. 'preload',
  14621. 'pubdate',
  14622. 'radiogroup',
  14623. 'readonly',
  14624. 'rel',
  14625. 'required',
  14626. 'rev',
  14627. 'reversed',
  14628. 'role',
  14629. 'rows',
  14630. 'rowspan',
  14631. 'spellcheck',
  14632. 'scope',
  14633. 'selected',
  14634. 'shape',
  14635. 'size',
  14636. 'sizes',
  14637. 'span',
  14638. 'srclang',
  14639. 'start',
  14640. 'src',
  14641. 'srcset',
  14642. 'step',
  14643. 'style',
  14644. 'summary',
  14645. 'tabindex',
  14646. 'title',
  14647. 'translate',
  14648. 'type',
  14649. 'usemap',
  14650. 'valign',
  14651. 'value',
  14652. 'width',
  14653. 'xmlns',
  14654. 'slot'
  14655. ]);
  14656. var svg = freeze([
  14657. 'accent-height',
  14658. 'accumulate',
  14659. 'additive',
  14660. 'alignment-baseline',
  14661. 'ascent',
  14662. 'attributename',
  14663. 'attributetype',
  14664. 'azimuth',
  14665. 'basefrequency',
  14666. 'baseline-shift',
  14667. 'begin',
  14668. 'bias',
  14669. 'by',
  14670. 'class',
  14671. 'clip',
  14672. 'clippathunits',
  14673. 'clip-path',
  14674. 'clip-rule',
  14675. 'color',
  14676. 'color-interpolation',
  14677. 'color-interpolation-filters',
  14678. 'color-profile',
  14679. 'color-rendering',
  14680. 'cx',
  14681. 'cy',
  14682. 'd',
  14683. 'dx',
  14684. 'dy',
  14685. 'diffuseconstant',
  14686. 'direction',
  14687. 'display',
  14688. 'divisor',
  14689. 'dur',
  14690. 'edgemode',
  14691. 'elevation',
  14692. 'end',
  14693. 'fill',
  14694. 'fill-opacity',
  14695. 'fill-rule',
  14696. 'filter',
  14697. 'filterunits',
  14698. 'flood-color',
  14699. 'flood-opacity',
  14700. 'font-family',
  14701. 'font-size',
  14702. 'font-size-adjust',
  14703. 'font-stretch',
  14704. 'font-style',
  14705. 'font-variant',
  14706. 'font-weight',
  14707. 'fx',
  14708. 'fy',
  14709. 'g1',
  14710. 'g2',
  14711. 'glyph-name',
  14712. 'glyphref',
  14713. 'gradientunits',
  14714. 'gradienttransform',
  14715. 'height',
  14716. 'href',
  14717. 'id',
  14718. 'image-rendering',
  14719. 'in',
  14720. 'in2',
  14721. 'k',
  14722. 'k1',
  14723. 'k2',
  14724. 'k3',
  14725. 'k4',
  14726. 'kerning',
  14727. 'keypoints',
  14728. 'keysplines',
  14729. 'keytimes',
  14730. 'lang',
  14731. 'lengthadjust',
  14732. 'letter-spacing',
  14733. 'kernelmatrix',
  14734. 'kernelunitlength',
  14735. 'lighting-color',
  14736. 'local',
  14737. 'marker-end',
  14738. 'marker-mid',
  14739. 'marker-start',
  14740. 'markerheight',
  14741. 'markerunits',
  14742. 'markerwidth',
  14743. 'maskcontentunits',
  14744. 'maskunits',
  14745. 'max',
  14746. 'mask',
  14747. 'media',
  14748. 'method',
  14749. 'mode',
  14750. 'min',
  14751. 'name',
  14752. 'numoctaves',
  14753. 'offset',
  14754. 'operator',
  14755. 'opacity',
  14756. 'order',
  14757. 'orient',
  14758. 'orientation',
  14759. 'origin',
  14760. 'overflow',
  14761. 'paint-order',
  14762. 'path',
  14763. 'pathlength',
  14764. 'patterncontentunits',
  14765. 'patterntransform',
  14766. 'patternunits',
  14767. 'points',
  14768. 'preservealpha',
  14769. 'preserveaspectratio',
  14770. 'primitiveunits',
  14771. 'r',
  14772. 'rx',
  14773. 'ry',
  14774. 'radius',
  14775. 'refx',
  14776. 'refy',
  14777. 'repeatcount',
  14778. 'repeatdur',
  14779. 'restart',
  14780. 'result',
  14781. 'rotate',
  14782. 'scale',
  14783. 'seed',
  14784. 'shape-rendering',
  14785. 'specularconstant',
  14786. 'specularexponent',
  14787. 'spreadmethod',
  14788. 'startoffset',
  14789. 'stddeviation',
  14790. 'stitchtiles',
  14791. 'stop-color',
  14792. 'stop-opacity',
  14793. 'stroke-dasharray',
  14794. 'stroke-dashoffset',
  14795. 'stroke-linecap',
  14796. 'stroke-linejoin',
  14797. 'stroke-miterlimit',
  14798. 'stroke-opacity',
  14799. 'stroke',
  14800. 'stroke-width',
  14801. 'style',
  14802. 'surfacescale',
  14803. 'systemlanguage',
  14804. 'tabindex',
  14805. 'targetx',
  14806. 'targety',
  14807. 'transform',
  14808. 'transform-origin',
  14809. 'text-anchor',
  14810. 'text-decoration',
  14811. 'text-rendering',
  14812. 'textlength',
  14813. 'type',
  14814. 'u1',
  14815. 'u2',
  14816. 'unicode',
  14817. 'values',
  14818. 'viewbox',
  14819. 'visibility',
  14820. 'version',
  14821. 'vert-adv-y',
  14822. 'vert-origin-x',
  14823. 'vert-origin-y',
  14824. 'width',
  14825. 'word-spacing',
  14826. 'wrap',
  14827. 'writing-mode',
  14828. 'xchannelselector',
  14829. 'ychannelselector',
  14830. 'x',
  14831. 'x1',
  14832. 'x2',
  14833. 'xmlns',
  14834. 'y',
  14835. 'y1',
  14836. 'y2',
  14837. 'z',
  14838. 'zoomandpan'
  14839. ]);
  14840. var mathMl = freeze([
  14841. 'accent',
  14842. 'accentunder',
  14843. 'align',
  14844. 'bevelled',
  14845. 'close',
  14846. 'columnsalign',
  14847. 'columnlines',
  14848. 'columnspan',
  14849. 'denomalign',
  14850. 'depth',
  14851. 'dir',
  14852. 'display',
  14853. 'displaystyle',
  14854. 'encoding',
  14855. 'fence',
  14856. 'frame',
  14857. 'height',
  14858. 'href',
  14859. 'id',
  14860. 'largeop',
  14861. 'length',
  14862. 'linethickness',
  14863. 'lspace',
  14864. 'lquote',
  14865. 'mathbackground',
  14866. 'mathcolor',
  14867. 'mathsize',
  14868. 'mathvariant',
  14869. 'maxsize',
  14870. 'minsize',
  14871. 'movablelimits',
  14872. 'notation',
  14873. 'numalign',
  14874. 'open',
  14875. 'rowalign',
  14876. 'rowlines',
  14877. 'rowspacing',
  14878. 'rowspan',
  14879. 'rspace',
  14880. 'rquote',
  14881. 'scriptlevel',
  14882. 'scriptminsize',
  14883. 'scriptsizemultiplier',
  14884. 'selection',
  14885. 'separator',
  14886. 'separators',
  14887. 'stretchy',
  14888. 'subscriptshift',
  14889. 'supscriptshift',
  14890. 'symmetric',
  14891. 'voffset',
  14892. 'width',
  14893. 'xmlns'
  14894. ]);
  14895. var xml = freeze([
  14896. 'xlink:href',
  14897. 'xml:id',
  14898. 'xlink:title',
  14899. 'xml:space',
  14900. 'xmlns:xlink'
  14901. ]);
  14902. var MUSTACHE_EXPR = seal(/\{\{[\w\W]*|[\w\W]*\}\}/gm);
  14903. var ERB_EXPR = seal(/<%[\w\W]*|[\w\W]*%>/gm);
  14904. var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/);
  14905. var ARIA_ATTR = seal(/^aria-[\-\w]+$/);
  14906. var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i);
  14907. var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
  14908. var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g);
  14909. var DOCTYPE_NAME = seal(/^html$/i);
  14910. var getGlobal = function getGlobal() {
  14911. return typeof window === 'undefined' ? null : window;
  14912. };
  14913. var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
  14914. if (_typeof(trustedTypes) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
  14915. return null;
  14916. }
  14917. var suffix = null;
  14918. var ATTR_NAME = 'data-tt-policy-suffix';
  14919. if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
  14920. suffix = document.currentScript.getAttribute(ATTR_NAME);
  14921. }
  14922. var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
  14923. try {
  14924. return trustedTypes.createPolicy(policyName, {
  14925. createHTML: function createHTML(html) {
  14926. return html;
  14927. }
  14928. });
  14929. } catch (_) {
  14930. console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
  14931. return null;
  14932. }
  14933. };
  14934. function createDOMPurify() {
  14935. var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
  14936. var DOMPurify = function DOMPurify(root) {
  14937. return createDOMPurify(root);
  14938. };
  14939. DOMPurify.version = '2.3.8';
  14940. DOMPurify.removed = [];
  14941. if (!window || !window.document || window.document.nodeType !== 9) {
  14942. DOMPurify.isSupported = false;
  14943. return DOMPurify;
  14944. }
  14945. var originalDocument = window.document;
  14946. var document = window.document;
  14947. var DocumentFragment = window.DocumentFragment, HTMLTemplateElement = window.HTMLTemplateElement, Node = window.Node, Element = window.Element, NodeFilter = window.NodeFilter, _window$NamedNodeMap = window.NamedNodeMap, NamedNodeMap = _window$NamedNodeMap === void 0 ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap, HTMLFormElement = window.HTMLFormElement, DOMParser = window.DOMParser, trustedTypes = window.trustedTypes;
  14948. var ElementPrototype = Element.prototype;
  14949. var cloneNode = lookupGetter(ElementPrototype, 'cloneNode');
  14950. var getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');
  14951. var getChildNodes = lookupGetter(ElementPrototype, 'childNodes');
  14952. var getParentNode = lookupGetter(ElementPrototype, 'parentNode');
  14953. if (typeof HTMLTemplateElement === 'function') {
  14954. var template = document.createElement('template');
  14955. if (template.content && template.content.ownerDocument) {
  14956. document = template.content.ownerDocument;
  14957. }
  14958. }
  14959. var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
  14960. var emptyHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML('') : '';
  14961. var _document = document, implementation = _document.implementation, createNodeIterator = _document.createNodeIterator, createDocumentFragment = _document.createDocumentFragment, getElementsByTagName = _document.getElementsByTagName;
  14962. var importNode = originalDocument.importNode;
  14963. var documentMode = {};
  14964. try {
  14965. documentMode = clone(document).documentMode ? document.documentMode : {};
  14966. } catch (_) {
  14967. }
  14968. var hooks = {};
  14969. DOMPurify.isSupported = typeof getParentNode === 'function' && implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
  14970. var MUSTACHE_EXPR$1 = MUSTACHE_EXPR, ERB_EXPR$1 = ERB_EXPR, DATA_ATTR$1 = DATA_ATTR, ARIA_ATTR$1 = ARIA_ATTR, IS_SCRIPT_OR_DATA$1 = IS_SCRIPT_OR_DATA, ATTR_WHITESPACE$1 = ATTR_WHITESPACE;
  14971. var IS_ALLOWED_URI$1 = IS_ALLOWED_URI;
  14972. var ALLOWED_TAGS = null;
  14973. var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(svgFilters), _toConsumableArray(mathMl$1), _toConsumableArray(text)));
  14974. var ALLOWED_ATTR = null;
  14975. var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(mathMl), _toConsumableArray(xml)));
  14976. var CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {
  14977. tagNameCheck: {
  14978. writable: true,
  14979. configurable: false,
  14980. enumerable: true,
  14981. value: null
  14982. },
  14983. attributeNameCheck: {
  14984. writable: true,
  14985. configurable: false,
  14986. enumerable: true,
  14987. value: null
  14988. },
  14989. allowCustomizedBuiltInElements: {
  14990. writable: true,
  14991. configurable: false,
  14992. enumerable: true,
  14993. value: false
  14994. }
  14995. }));
  14996. var FORBID_TAGS = null;
  14997. var FORBID_ATTR = null;
  14998. var ALLOW_ARIA_ATTR = true;
  14999. var ALLOW_DATA_ATTR = true;
  15000. var ALLOW_UNKNOWN_PROTOCOLS = false;
  15001. var SAFE_FOR_TEMPLATES = false;
  15002. var WHOLE_DOCUMENT = false;
  15003. var SET_CONFIG = false;
  15004. var FORCE_BODY = false;
  15005. var RETURN_DOM = false;
  15006. var RETURN_DOM_FRAGMENT = false;
  15007. var RETURN_TRUSTED_TYPE = false;
  15008. var SANITIZE_DOM = true;
  15009. var KEEP_CONTENT = true;
  15010. var IN_PLACE = false;
  15011. var USE_PROFILES = {};
  15012. var FORBID_CONTENTS = null;
  15013. var DEFAULT_FORBID_CONTENTS = addToSet({}, [
  15014. 'annotation-xml',
  15015. 'audio',
  15016. 'colgroup',
  15017. 'desc',
  15018. 'foreignobject',
  15019. 'head',
  15020. 'iframe',
  15021. 'math',
  15022. 'mi',
  15023. 'mn',
  15024. 'mo',
  15025. 'ms',
  15026. 'mtext',
  15027. 'noembed',
  15028. 'noframes',
  15029. 'noscript',
  15030. 'plaintext',
  15031. 'script',
  15032. 'style',
  15033. 'svg',
  15034. 'template',
  15035. 'thead',
  15036. 'title',
  15037. 'video',
  15038. 'xmp'
  15039. ]);
  15040. var DATA_URI_TAGS = null;
  15041. var DEFAULT_DATA_URI_TAGS = addToSet({}, [
  15042. 'audio',
  15043. 'video',
  15044. 'img',
  15045. 'source',
  15046. 'image',
  15047. 'track'
  15048. ]);
  15049. var URI_SAFE_ATTRIBUTES = null;
  15050. var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, [
  15051. 'alt',
  15052. 'class',
  15053. 'for',
  15054. 'id',
  15055. 'label',
  15056. 'name',
  15057. 'pattern',
  15058. 'placeholder',
  15059. 'role',
  15060. 'summary',
  15061. 'title',
  15062. 'value',
  15063. 'style',
  15064. 'xmlns'
  15065. ]);
  15066. var MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';
  15067. var SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
  15068. var HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';
  15069. var NAMESPACE = HTML_NAMESPACE;
  15070. var IS_EMPTY_INPUT = false;
  15071. var PARSER_MEDIA_TYPE;
  15072. var SUPPORTED_PARSER_MEDIA_TYPES = [
  15073. 'application/xhtml+xml',
  15074. 'text/html'
  15075. ];
  15076. var DEFAULT_PARSER_MEDIA_TYPE = 'text/html';
  15077. var transformCaseFunc;
  15078. var CONFIG = null;
  15079. var formElement = document.createElement('form');
  15080. var isRegexOrFunction = function isRegexOrFunction(testValue) {
  15081. return testValue instanceof RegExp || testValue instanceof Function;
  15082. };
  15083. var _parseConfig = function _parseConfig(cfg) {
  15084. if (CONFIG && CONFIG === cfg) {
  15085. return;
  15086. }
  15087. if (!cfg || _typeof(cfg) !== 'object') {
  15088. cfg = {};
  15089. }
  15090. cfg = clone(cfg);
  15091. ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
  15092. ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
  15093. URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
  15094. DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
  15095. FORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS) : DEFAULT_FORBID_CONTENTS;
  15096. FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
  15097. FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
  15098. USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
  15099. ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false;
  15100. ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false;
  15101. ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false;
  15102. SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false;
  15103. WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false;
  15104. RETURN_DOM = cfg.RETURN_DOM || false;
  15105. RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false;
  15106. RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false;
  15107. FORCE_BODY = cfg.FORCE_BODY || false;
  15108. SANITIZE_DOM = cfg.SANITIZE_DOM !== false;
  15109. KEEP_CONTENT = cfg.KEEP_CONTENT !== false;
  15110. IN_PLACE = cfg.IN_PLACE || false;
  15111. IS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$1;
  15112. NAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;
  15113. if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {
  15114. CUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;
  15115. }
  15116. if (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {
  15117. CUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;
  15118. }
  15119. if (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {
  15120. CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;
  15121. }
  15122. PARSER_MEDIA_TYPE = SUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE;
  15123. transformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? function (x) {
  15124. return x;
  15125. } : stringToLowerCase;
  15126. if (SAFE_FOR_TEMPLATES) {
  15127. ALLOW_DATA_ATTR = false;
  15128. }
  15129. if (RETURN_DOM_FRAGMENT) {
  15130. RETURN_DOM = true;
  15131. }
  15132. if (USE_PROFILES) {
  15133. ALLOWED_TAGS = addToSet({}, _toConsumableArray(text));
  15134. ALLOWED_ATTR = [];
  15135. if (USE_PROFILES.html === true) {
  15136. addToSet(ALLOWED_TAGS, html$1);
  15137. addToSet(ALLOWED_ATTR, html);
  15138. }
  15139. if (USE_PROFILES.svg === true) {
  15140. addToSet(ALLOWED_TAGS, svg$1);
  15141. addToSet(ALLOWED_ATTR, svg);
  15142. addToSet(ALLOWED_ATTR, xml);
  15143. }
  15144. if (USE_PROFILES.svgFilters === true) {
  15145. addToSet(ALLOWED_TAGS, svgFilters);
  15146. addToSet(ALLOWED_ATTR, svg);
  15147. addToSet(ALLOWED_ATTR, xml);
  15148. }
  15149. if (USE_PROFILES.mathMl === true) {
  15150. addToSet(ALLOWED_TAGS, mathMl$1);
  15151. addToSet(ALLOWED_ATTR, mathMl);
  15152. addToSet(ALLOWED_ATTR, xml);
  15153. }
  15154. }
  15155. if (cfg.ADD_TAGS) {
  15156. if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
  15157. ALLOWED_TAGS = clone(ALLOWED_TAGS);
  15158. }
  15159. addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
  15160. }
  15161. if (cfg.ADD_ATTR) {
  15162. if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
  15163. ALLOWED_ATTR = clone(ALLOWED_ATTR);
  15164. }
  15165. addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
  15166. }
  15167. if (cfg.ADD_URI_SAFE_ATTR) {
  15168. addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
  15169. }
  15170. if (cfg.FORBID_CONTENTS) {
  15171. if (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {
  15172. FORBID_CONTENTS = clone(FORBID_CONTENTS);
  15173. }
  15174. addToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS);
  15175. }
  15176. if (KEEP_CONTENT) {
  15177. ALLOWED_TAGS['#text'] = true;
  15178. }
  15179. if (WHOLE_DOCUMENT) {
  15180. addToSet(ALLOWED_TAGS, [
  15181. 'html',
  15182. 'head',
  15183. 'body'
  15184. ]);
  15185. }
  15186. if (ALLOWED_TAGS.table) {
  15187. addToSet(ALLOWED_TAGS, ['tbody']);
  15188. delete FORBID_TAGS.tbody;
  15189. }
  15190. if (freeze) {
  15191. freeze(cfg);
  15192. }
  15193. CONFIG = cfg;
  15194. };
  15195. var MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, [
  15196. 'mi',
  15197. 'mo',
  15198. 'mn',
  15199. 'ms',
  15200. 'mtext'
  15201. ]);
  15202. var HTML_INTEGRATION_POINTS = addToSet({}, [
  15203. 'foreignobject',
  15204. 'desc',
  15205. 'title',
  15206. 'annotation-xml'
  15207. ]);
  15208. var COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, [
  15209. 'title',
  15210. 'style',
  15211. 'font',
  15212. 'a',
  15213. 'script'
  15214. ]);
  15215. var ALL_SVG_TAGS = addToSet({}, svg$1);
  15216. addToSet(ALL_SVG_TAGS, svgFilters);
  15217. addToSet(ALL_SVG_TAGS, svgDisallowed);
  15218. var ALL_MATHML_TAGS = addToSet({}, mathMl$1);
  15219. addToSet(ALL_MATHML_TAGS, mathMlDisallowed);
  15220. var _checkValidNamespace = function _checkValidNamespace(element) {
  15221. var parent = getParentNode(element);
  15222. if (!parent || !parent.tagName) {
  15223. parent = {
  15224. namespaceURI: HTML_NAMESPACE,
  15225. tagName: 'template'
  15226. };
  15227. }
  15228. var tagName = stringToLowerCase(element.tagName);
  15229. var parentTagName = stringToLowerCase(parent.tagName);
  15230. if (element.namespaceURI === SVG_NAMESPACE) {
  15231. if (parent.namespaceURI === HTML_NAMESPACE) {
  15232. return tagName === 'svg';
  15233. }
  15234. if (parent.namespaceURI === MATHML_NAMESPACE) {
  15235. return tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);
  15236. }
  15237. return Boolean(ALL_SVG_TAGS[tagName]);
  15238. }
  15239. if (element.namespaceURI === MATHML_NAMESPACE) {
  15240. if (parent.namespaceURI === HTML_NAMESPACE) {
  15241. return tagName === 'math';
  15242. }
  15243. if (parent.namespaceURI === SVG_NAMESPACE) {
  15244. return tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];
  15245. }
  15246. return Boolean(ALL_MATHML_TAGS[tagName]);
  15247. }
  15248. if (element.namespaceURI === HTML_NAMESPACE) {
  15249. if (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {
  15250. return false;
  15251. }
  15252. if (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {
  15253. return false;
  15254. }
  15255. return !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);
  15256. }
  15257. return false;
  15258. };
  15259. var _forceRemove = function _forceRemove(node) {
  15260. arrayPush(DOMPurify.removed, { element: node });
  15261. try {
  15262. node.parentNode.removeChild(node);
  15263. } catch (_) {
  15264. try {
  15265. node.outerHTML = emptyHTML;
  15266. } catch (_) {
  15267. node.remove();
  15268. }
  15269. }
  15270. };
  15271. var _removeAttribute = function _removeAttribute(name, node) {
  15272. try {
  15273. arrayPush(DOMPurify.removed, {
  15274. attribute: node.getAttributeNode(name),
  15275. from: node
  15276. });
  15277. } catch (_) {
  15278. arrayPush(DOMPurify.removed, {
  15279. attribute: null,
  15280. from: node
  15281. });
  15282. }
  15283. node.removeAttribute(name);
  15284. if (name === 'is' && !ALLOWED_ATTR[name]) {
  15285. if (RETURN_DOM || RETURN_DOM_FRAGMENT) {
  15286. try {
  15287. _forceRemove(node);
  15288. } catch (_) {
  15289. }
  15290. } else {
  15291. try {
  15292. node.setAttribute(name, '');
  15293. } catch (_) {
  15294. }
  15295. }
  15296. }
  15297. };
  15298. var _initDocument = function _initDocument(dirty) {
  15299. var doc;
  15300. var leadingWhitespace;
  15301. if (FORCE_BODY) {
  15302. dirty = '<remove></remove>' + dirty;
  15303. } else {
  15304. var matches = stringMatch(dirty, /^[\r\n\t ]+/);
  15305. leadingWhitespace = matches && matches[0];
  15306. }
  15307. if (PARSER_MEDIA_TYPE === 'application/xhtml+xml') {
  15308. dirty = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' + dirty + '</body></html>';
  15309. }
  15310. var dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;
  15311. if (NAMESPACE === HTML_NAMESPACE) {
  15312. try {
  15313. doc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);
  15314. } catch (_) {
  15315. }
  15316. }
  15317. if (!doc || !doc.documentElement) {
  15318. doc = implementation.createDocument(NAMESPACE, 'template', null);
  15319. try {
  15320. doc.documentElement.innerHTML = IS_EMPTY_INPUT ? '' : dirtyPayload;
  15321. } catch (_) {
  15322. }
  15323. }
  15324. var body = doc.body || doc.documentElement;
  15325. if (dirty && leadingWhitespace) {
  15326. body.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);
  15327. }
  15328. if (NAMESPACE === HTML_NAMESPACE) {
  15329. return getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];
  15330. }
  15331. return WHOLE_DOCUMENT ? doc.documentElement : body;
  15332. };
  15333. var _createIterator = function _createIterator(root) {
  15334. return createNodeIterator.call(root.ownerDocument || root, root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);
  15335. };
  15336. var _isClobbered = function _isClobbered(elm) {
  15337. return elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function');
  15338. };
  15339. var _isNode = function _isNode(object) {
  15340. return _typeof(Node) === 'object' ? object instanceof Node : object && _typeof(object) === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';
  15341. };
  15342. var _executeHook = function _executeHook(entryPoint, currentNode, data) {
  15343. if (!hooks[entryPoint]) {
  15344. return;
  15345. }
  15346. arrayForEach(hooks[entryPoint], function (hook) {
  15347. hook.call(DOMPurify, currentNode, data, CONFIG);
  15348. });
  15349. };
  15350. var _sanitizeElements = function _sanitizeElements(currentNode) {
  15351. var content;
  15352. _executeHook('beforeSanitizeElements', currentNode, null);
  15353. if (_isClobbered(currentNode)) {
  15354. _forceRemove(currentNode);
  15355. return true;
  15356. }
  15357. if (regExpTest(/[\u0080-\uFFFF]/, currentNode.nodeName)) {
  15358. _forceRemove(currentNode);
  15359. return true;
  15360. }
  15361. var tagName = transformCaseFunc(currentNode.nodeName);
  15362. _executeHook('uponSanitizeElement', currentNode, {
  15363. tagName: tagName,
  15364. allowedTags: ALLOWED_TAGS
  15365. });
  15366. if (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\w]/g, currentNode.innerHTML) && regExpTest(/<[/\w]/g, currentNode.textContent)) {
  15367. _forceRemove(currentNode);
  15368. return true;
  15369. }
  15370. if (tagName === 'select' && regExpTest(/<template/i, currentNode.innerHTML)) {
  15371. _forceRemove(currentNode);
  15372. return true;
  15373. }
  15374. if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
  15375. if (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {
  15376. if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName))
  15377. return false;
  15378. if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName))
  15379. return false;
  15380. }
  15381. if (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {
  15382. var parentNode = getParentNode(currentNode) || currentNode.parentNode;
  15383. var childNodes = getChildNodes(currentNode) || currentNode.childNodes;
  15384. if (childNodes && parentNode) {
  15385. var childCount = childNodes.length;
  15386. for (var i = childCount - 1; i >= 0; --i) {
  15387. parentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));
  15388. }
  15389. }
  15390. }
  15391. _forceRemove(currentNode);
  15392. return true;
  15393. }
  15394. if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
  15395. _forceRemove(currentNode);
  15396. return true;
  15397. }
  15398. if ((tagName === 'noscript' || tagName === 'noembed') && regExpTest(/<\/no(script|embed)/i, currentNode.innerHTML)) {
  15399. _forceRemove(currentNode);
  15400. return true;
  15401. }
  15402. if (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {
  15403. content = currentNode.textContent;
  15404. content = stringReplace(content, MUSTACHE_EXPR$1, ' ');
  15405. content = stringReplace(content, ERB_EXPR$1, ' ');
  15406. if (currentNode.textContent !== content) {
  15407. arrayPush(DOMPurify.removed, { element: currentNode.cloneNode() });
  15408. currentNode.textContent = content;
  15409. }
  15410. }
  15411. _executeHook('afterSanitizeElements', currentNode, null);
  15412. return false;
  15413. };
  15414. var _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {
  15415. if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
  15416. return false;
  15417. }
  15418. if (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR$1, lcName));
  15419. else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR$1, lcName));
  15420. else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {
  15421. if (_basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || lcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value)));
  15422. else {
  15423. return false;
  15424. }
  15425. } else if (URI_SAFE_ATTRIBUTES[lcName]);
  15426. else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
  15427. else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]);
  15428. else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA$1, stringReplace(value, ATTR_WHITESPACE$1, '')));
  15429. else if (!value);
  15430. else {
  15431. return false;
  15432. }
  15433. return true;
  15434. };
  15435. var _basicCustomElementTest = function _basicCustomElementTest(tagName) {
  15436. return tagName.indexOf('-') > 0;
  15437. };
  15438. var _sanitizeAttributes = function _sanitizeAttributes(currentNode) {
  15439. var attr;
  15440. var value;
  15441. var lcName;
  15442. var l;
  15443. _executeHook('beforeSanitizeAttributes', currentNode, null);
  15444. var attributes = currentNode.attributes;
  15445. if (!attributes) {
  15446. return;
  15447. }
  15448. var hookEvent = {
  15449. attrName: '',
  15450. attrValue: '',
  15451. keepAttr: true,
  15452. allowedAttributes: ALLOWED_ATTR
  15453. };
  15454. l = attributes.length;
  15455. while (l--) {
  15456. attr = attributes[l];
  15457. var _attr = attr, name = _attr.name, namespaceURI = _attr.namespaceURI;
  15458. value = name === 'value' ? attr.value : stringTrim(attr.value);
  15459. lcName = transformCaseFunc(name);
  15460. var initValue = value;
  15461. hookEvent.attrName = lcName;
  15462. hookEvent.attrValue = value;
  15463. hookEvent.keepAttr = true;
  15464. hookEvent.forceKeepAttr = undefined;
  15465. _executeHook('uponSanitizeAttribute', currentNode, hookEvent);
  15466. value = hookEvent.attrValue;
  15467. if (hookEvent.forceKeepAttr) {
  15468. continue;
  15469. }
  15470. if (!hookEvent.keepAttr) {
  15471. _removeAttribute(name, currentNode);
  15472. continue;
  15473. }
  15474. if (regExpTest(/\/>/i, value)) {
  15475. _removeAttribute(name, currentNode);
  15476. continue;
  15477. }
  15478. if (SAFE_FOR_TEMPLATES) {
  15479. value = stringReplace(value, MUSTACHE_EXPR$1, ' ');
  15480. value = stringReplace(value, ERB_EXPR$1, ' ');
  15481. }
  15482. var lcTag = transformCaseFunc(currentNode.nodeName);
  15483. if (!_isValidAttribute(lcTag, lcName, value)) {
  15484. _removeAttribute(name, currentNode);
  15485. continue;
  15486. }
  15487. if (value !== initValue) {
  15488. try {
  15489. if (namespaceURI) {
  15490. currentNode.setAttributeNS(namespaceURI, name, value);
  15491. } else {
  15492. currentNode.setAttribute(name, value);
  15493. }
  15494. } catch (_) {
  15495. _removeAttribute(name, currentNode);
  15496. }
  15497. }
  15498. }
  15499. _executeHook('afterSanitizeAttributes', currentNode, null);
  15500. };
  15501. var _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {
  15502. var shadowNode;
  15503. var shadowIterator = _createIterator(fragment);
  15504. _executeHook('beforeSanitizeShadowDOM', fragment, null);
  15505. while (shadowNode = shadowIterator.nextNode()) {
  15506. _executeHook('uponSanitizeShadowNode', shadowNode, null);
  15507. if (_sanitizeElements(shadowNode)) {
  15508. continue;
  15509. }
  15510. if (shadowNode.content instanceof DocumentFragment) {
  15511. _sanitizeShadowDOM(shadowNode.content);
  15512. }
  15513. _sanitizeAttributes(shadowNode);
  15514. }
  15515. _executeHook('afterSanitizeShadowDOM', fragment, null);
  15516. };
  15517. DOMPurify.sanitize = function (dirty, cfg) {
  15518. var body;
  15519. var importedNode;
  15520. var currentNode;
  15521. var oldNode;
  15522. var returnNode;
  15523. IS_EMPTY_INPUT = !dirty;
  15524. if (IS_EMPTY_INPUT) {
  15525. dirty = '<!-->';
  15526. }
  15527. if (typeof dirty !== 'string' && !_isNode(dirty)) {
  15528. if (typeof dirty.toString !== 'function') {
  15529. throw typeErrorCreate('toString is not a function');
  15530. } else {
  15531. dirty = dirty.toString();
  15532. if (typeof dirty !== 'string') {
  15533. throw typeErrorCreate('dirty is not a string, aborting');
  15534. }
  15535. }
  15536. }
  15537. if (!DOMPurify.isSupported) {
  15538. if (_typeof(window.toStaticHTML) === 'object' || typeof window.toStaticHTML === 'function') {
  15539. if (typeof dirty === 'string') {
  15540. return window.toStaticHTML(dirty);
  15541. }
  15542. if (_isNode(dirty)) {
  15543. return window.toStaticHTML(dirty.outerHTML);
  15544. }
  15545. }
  15546. return dirty;
  15547. }
  15548. if (!SET_CONFIG) {
  15549. _parseConfig(cfg);
  15550. }
  15551. DOMPurify.removed = [];
  15552. if (typeof dirty === 'string') {
  15553. IN_PLACE = false;
  15554. }
  15555. if (IN_PLACE) {
  15556. if (dirty.nodeName) {
  15557. var tagName = transformCaseFunc(dirty.nodeName);
  15558. if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
  15559. throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
  15560. }
  15561. }
  15562. } else if (dirty instanceof Node) {
  15563. body = _initDocument('<!---->');
  15564. importedNode = body.ownerDocument.importNode(dirty, true);
  15565. if (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {
  15566. body = importedNode;
  15567. } else if (importedNode.nodeName === 'HTML') {
  15568. body = importedNode;
  15569. } else {
  15570. body.appendChild(importedNode);
  15571. }
  15572. } else {
  15573. if (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && dirty.indexOf('<') === -1) {
  15574. return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;
  15575. }
  15576. body = _initDocument(dirty);
  15577. if (!body) {
  15578. return RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';
  15579. }
  15580. }
  15581. if (body && FORCE_BODY) {
  15582. _forceRemove(body.firstChild);
  15583. }
  15584. var nodeIterator = _createIterator(IN_PLACE ? dirty : body);
  15585. while (currentNode = nodeIterator.nextNode()) {
  15586. if (currentNode.nodeType === 3 && currentNode === oldNode) {
  15587. continue;
  15588. }
  15589. if (_sanitizeElements(currentNode)) {
  15590. continue;
  15591. }
  15592. if (currentNode.content instanceof DocumentFragment) {
  15593. _sanitizeShadowDOM(currentNode.content);
  15594. }
  15595. _sanitizeAttributes(currentNode);
  15596. oldNode = currentNode;
  15597. }
  15598. oldNode = null;
  15599. if (IN_PLACE) {
  15600. return dirty;
  15601. }
  15602. if (RETURN_DOM) {
  15603. if (RETURN_DOM_FRAGMENT) {
  15604. returnNode = createDocumentFragment.call(body.ownerDocument);
  15605. while (body.firstChild) {
  15606. returnNode.appendChild(body.firstChild);
  15607. }
  15608. } else {
  15609. returnNode = body;
  15610. }
  15611. if (ALLOWED_ATTR.shadowroot) {
  15612. returnNode = importNode.call(originalDocument, returnNode, true);
  15613. }
  15614. return returnNode;
  15615. }
  15616. var serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;
  15617. if (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {
  15618. serializedHTML = '<!DOCTYPE ' + body.ownerDocument.doctype.name + '>\n' + serializedHTML;
  15619. }
  15620. if (SAFE_FOR_TEMPLATES) {
  15621. serializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR$1, ' ');
  15622. serializedHTML = stringReplace(serializedHTML, ERB_EXPR$1, ' ');
  15623. }
  15624. return trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;
  15625. };
  15626. DOMPurify.setConfig = function (cfg) {
  15627. _parseConfig(cfg);
  15628. SET_CONFIG = true;
  15629. };
  15630. DOMPurify.clearConfig = function () {
  15631. CONFIG = null;
  15632. SET_CONFIG = false;
  15633. };
  15634. DOMPurify.isValidAttribute = function (tag, attr, value) {
  15635. if (!CONFIG) {
  15636. _parseConfig({});
  15637. }
  15638. var lcTag = transformCaseFunc(tag);
  15639. var lcName = transformCaseFunc(attr);
  15640. return _isValidAttribute(lcTag, lcName, value);
  15641. };
  15642. DOMPurify.addHook = function (entryPoint, hookFunction) {
  15643. if (typeof hookFunction !== 'function') {
  15644. return;
  15645. }
  15646. hooks[entryPoint] = hooks[entryPoint] || [];
  15647. arrayPush(hooks[entryPoint], hookFunction);
  15648. };
  15649. DOMPurify.removeHook = function (entryPoint) {
  15650. if (hooks[entryPoint]) {
  15651. return arrayPop(hooks[entryPoint]);
  15652. }
  15653. };
  15654. DOMPurify.removeHooks = function (entryPoint) {
  15655. if (hooks[entryPoint]) {
  15656. hooks[entryPoint] = [];
  15657. }
  15658. };
  15659. DOMPurify.removeAllHooks = function () {
  15660. hooks = {};
  15661. };
  15662. return DOMPurify;
  15663. }
  15664. var purify = createDOMPurify();
  15665. const explode$1 = Tools.explode;
  15666. const create$7 = () => {
  15667. const filters = {};
  15668. const addFilter = (name, callback) => {
  15669. each$e(explode$1(name), name => {
  15670. if (!has$2(filters, name)) {
  15671. filters[name] = {
  15672. name,
  15673. callbacks: []
  15674. };
  15675. }
  15676. filters[name].callbacks.push(callback);
  15677. });
  15678. };
  15679. const getFilters = () => values(filters);
  15680. const removeFilter = (name, callback) => {
  15681. each$e(explode$1(name), name => {
  15682. if (has$2(filters, name)) {
  15683. if (isNonNullable(callback)) {
  15684. const filter = filters[name];
  15685. const newCallbacks = filter$5(filter.callbacks, c => c !== callback);
  15686. if (newCallbacks.length > 0) {
  15687. filter.callbacks = newCallbacks;
  15688. } else {
  15689. delete filters[name];
  15690. }
  15691. } else {
  15692. delete filters[name];
  15693. }
  15694. }
  15695. });
  15696. };
  15697. return {
  15698. addFilter,
  15699. getFilters,
  15700. removeFilter
  15701. };
  15702. };
  15703. const removeAttrs = (node, names) => {
  15704. each$e(names, name => {
  15705. node.attr(name, null);
  15706. });
  15707. };
  15708. const addFontToSpansFilter = (domParser, styles, fontSizes) => {
  15709. domParser.addNodeFilter('font', nodes => {
  15710. each$e(nodes, node => {
  15711. const props = styles.parse(node.attr('style'));
  15712. const color = node.attr('color');
  15713. const face = node.attr('face');
  15714. const size = node.attr('size');
  15715. if (color) {
  15716. props.color = color;
  15717. }
  15718. if (face) {
  15719. props['font-family'] = face;
  15720. }
  15721. if (size) {
  15722. toInt(size).each(num => {
  15723. props['font-size'] = fontSizes[num - 1];
  15724. });
  15725. }
  15726. node.name = 'span';
  15727. node.attr('style', styles.serialize(props));
  15728. removeAttrs(node, [
  15729. 'color',
  15730. 'face',
  15731. 'size'
  15732. ]);
  15733. });
  15734. });
  15735. };
  15736. const addStrikeFilter = (domParser, schema, styles) => {
  15737. domParser.addNodeFilter('strike', nodes => {
  15738. const convertToSTag = schema.type !== 'html4';
  15739. each$e(nodes, node => {
  15740. if (convertToSTag) {
  15741. node.name = 's';
  15742. } else {
  15743. const props = styles.parse(node.attr('style'));
  15744. props['text-decoration'] = 'line-through';
  15745. node.name = 'span';
  15746. node.attr('style', styles.serialize(props));
  15747. }
  15748. });
  15749. });
  15750. };
  15751. const addFilters = (domParser, settings, schema) => {
  15752. var _a;
  15753. const styles = Styles();
  15754. if (settings.convert_fonts_to_spans) {
  15755. addFontToSpansFilter(domParser, styles, Tools.explode((_a = settings.font_size_legacy_values) !== null && _a !== void 0 ? _a : ''));
  15756. }
  15757. addStrikeFilter(domParser, schema, styles);
  15758. };
  15759. const register$5 = (domParser, settings, schema) => {
  15760. if (settings.inline_styles) {
  15761. addFilters(domParser, settings, schema);
  15762. }
  15763. };
  15764. const blobUriToBlob = url => fetch(url).then(res => res.ok ? res.blob() : Promise.reject()).catch(() => Promise.reject(`Cannot convert ${ url } to Blob. Resource might not exist or is inaccessible.`));
  15765. const extractBase64Data = data => {
  15766. const matches = /([a-z0-9+\/=\s]+)/i.exec(data);
  15767. return matches ? matches[1] : '';
  15768. };
  15769. const parseDataUri = uri => {
  15770. const [type, ...rest] = uri.split(',');
  15771. const data = rest.join(',');
  15772. const matches = /data:([^/]+\/[^;]+)(;.+)?/.exec(type);
  15773. if (matches) {
  15774. const base64Encoded = matches[2] === ';base64';
  15775. const extractedData = base64Encoded ? extractBase64Data(data) : decodeURIComponent(data);
  15776. return Optional.some({
  15777. type: matches[1],
  15778. data: extractedData,
  15779. base64Encoded
  15780. });
  15781. } else {
  15782. return Optional.none();
  15783. }
  15784. };
  15785. const buildBlob = (type, data, base64Encoded = true) => {
  15786. let str = data;
  15787. if (base64Encoded) {
  15788. try {
  15789. str = atob(data);
  15790. } catch (e) {
  15791. return Optional.none();
  15792. }
  15793. }
  15794. const arr = new Uint8Array(str.length);
  15795. for (let i = 0; i < arr.length; i++) {
  15796. arr[i] = str.charCodeAt(i);
  15797. }
  15798. return Optional.some(new Blob([arr], { type }));
  15799. };
  15800. const dataUriToBlob = uri => {
  15801. return new Promise((resolve, reject) => {
  15802. parseDataUri(uri).bind(({type, data, base64Encoded}) => buildBlob(type, data, base64Encoded)).fold(() => reject('Invalid data URI'), resolve);
  15803. });
  15804. };
  15805. const uriToBlob = url => {
  15806. if (startsWith(url, 'blob:')) {
  15807. return blobUriToBlob(url);
  15808. } else if (startsWith(url, 'data:')) {
  15809. return dataUriToBlob(url);
  15810. } else {
  15811. return Promise.reject('Unknown URI format');
  15812. }
  15813. };
  15814. const blobToDataUri = blob => {
  15815. return new Promise((resolve, reject) => {
  15816. const reader = new FileReader();
  15817. reader.onloadend = () => {
  15818. resolve(reader.result);
  15819. };
  15820. reader.onerror = () => {
  15821. var _a;
  15822. reject((_a = reader.error) === null || _a === void 0 ? void 0 : _a.message);
  15823. };
  15824. reader.readAsDataURL(blob);
  15825. });
  15826. };
  15827. let count$1 = 0;
  15828. const uniqueId$1 = prefix => {
  15829. return (prefix || 'blobid') + count$1++;
  15830. };
  15831. const processDataUri = (dataUri, base64Only, generateBlobInfo) => {
  15832. return parseDataUri(dataUri).bind(({data, type, base64Encoded}) => {
  15833. if (base64Only && !base64Encoded) {
  15834. return Optional.none();
  15835. } else {
  15836. const base64 = base64Encoded ? data : btoa(data);
  15837. return generateBlobInfo(base64, type);
  15838. }
  15839. });
  15840. };
  15841. const createBlobInfo$1 = (blobCache, blob, base64) => {
  15842. const blobInfo = blobCache.create(uniqueId$1(), blob, base64);
  15843. blobCache.add(blobInfo);
  15844. return blobInfo;
  15845. };
  15846. const dataUriToBlobInfo = (blobCache, dataUri, base64Only = false) => {
  15847. return processDataUri(dataUri, base64Only, (base64, type) => Optional.from(blobCache.getByData(base64, type)).orThunk(() => buildBlob(type, base64).map(blob => createBlobInfo$1(blobCache, blob, base64))));
  15848. };
  15849. const imageToBlobInfo = (blobCache, imageSrc) => {
  15850. const invalidDataUri = () => Promise.reject('Invalid data URI');
  15851. if (startsWith(imageSrc, 'blob:')) {
  15852. const blobInfo = blobCache.getByUri(imageSrc);
  15853. if (isNonNullable(blobInfo)) {
  15854. return Promise.resolve(blobInfo);
  15855. } else {
  15856. return uriToBlob(imageSrc).then(blob => {
  15857. return blobToDataUri(blob).then(dataUri => {
  15858. return processDataUri(dataUri, false, base64 => {
  15859. return Optional.some(createBlobInfo$1(blobCache, blob, base64));
  15860. }).getOrThunk(invalidDataUri);
  15861. });
  15862. });
  15863. }
  15864. } else if (startsWith(imageSrc, 'data:')) {
  15865. return dataUriToBlobInfo(blobCache, imageSrc).fold(invalidDataUri, blobInfo => Promise.resolve(blobInfo));
  15866. } else {
  15867. return Promise.reject('Unknown image data format');
  15868. }
  15869. };
  15870. const isBogusImage = img => isNonNullable(img.attr('data-mce-bogus'));
  15871. const isInternalImageSource = img => img.attr('src') === Env.transparentSrc || isNonNullable(img.attr('data-mce-placeholder'));
  15872. const registerBase64ImageFilter = (parser, settings) => {
  15873. const {blob_cache: blobCache} = settings;
  15874. if (blobCache) {
  15875. const processImage = img => {
  15876. const inputSrc = img.attr('src');
  15877. if (isInternalImageSource(img) || isBogusImage(img) || isNullable(inputSrc)) {
  15878. return;
  15879. }
  15880. dataUriToBlobInfo(blobCache, inputSrc, true).each(blobInfo => {
  15881. img.attr('src', blobInfo.blobUri());
  15882. });
  15883. };
  15884. parser.addAttributeFilter('src', nodes => each$e(nodes, processImage));
  15885. }
  15886. };
  15887. const register$4 = (parser, settings) => {
  15888. const schema = parser.schema;
  15889. if (settings.remove_trailing_brs) {
  15890. parser.addNodeFilter('br', (nodes, _, args) => {
  15891. const blockElements = Tools.extend({}, schema.getBlockElements());
  15892. const nonEmptyElements = schema.getNonEmptyElements();
  15893. const whitespaceElements = schema.getWhitespaceElements();
  15894. blockElements.body = 1;
  15895. const isBlock = node => node.name in blockElements && isTransparentAstInline(schema, node);
  15896. for (let i = 0, l = nodes.length; i < l; i++) {
  15897. let node = nodes[i];
  15898. let parent = node.parent;
  15899. if (parent && blockElements[parent.name] && node === parent.lastChild) {
  15900. let prev = node.prev;
  15901. while (prev) {
  15902. const prevName = prev.name;
  15903. if (prevName !== 'span' || prev.attr('data-mce-type') !== 'bookmark') {
  15904. if (prevName === 'br') {
  15905. node = null;
  15906. }
  15907. break;
  15908. }
  15909. prev = prev.prev;
  15910. }
  15911. if (node) {
  15912. node.remove();
  15913. if (isEmpty(schema, nonEmptyElements, whitespaceElements, parent)) {
  15914. const elementRule = schema.getElementRule(parent.name);
  15915. if (elementRule) {
  15916. if (elementRule.removeEmpty) {
  15917. parent.remove();
  15918. } else if (elementRule.paddEmpty) {
  15919. paddEmptyNode(args, isBlock, parent);
  15920. }
  15921. }
  15922. }
  15923. }
  15924. } else {
  15925. let lastParent = node;
  15926. while (parent && parent.firstChild === lastParent && parent.lastChild === lastParent) {
  15927. lastParent = parent;
  15928. if (blockElements[parent.name]) {
  15929. break;
  15930. }
  15931. parent = parent.parent;
  15932. }
  15933. if (lastParent === parent) {
  15934. const textNode = new AstNode('#text', 3);
  15935. textNode.value = nbsp;
  15936. node.replace(textNode);
  15937. }
  15938. }
  15939. }
  15940. });
  15941. }
  15942. parser.addAttributeFilter('href', nodes => {
  15943. let i = nodes.length;
  15944. const appendRel = rel => {
  15945. const parts = rel.split(' ').filter(p => p.length > 0);
  15946. return parts.concat(['noopener']).sort().join(' ');
  15947. };
  15948. const addNoOpener = rel => {
  15949. const newRel = rel ? Tools.trim(rel) : '';
  15950. if (!/\b(noopener)\b/g.test(newRel)) {
  15951. return appendRel(newRel);
  15952. } else {
  15953. return newRel;
  15954. }
  15955. };
  15956. if (!settings.allow_unsafe_link_target) {
  15957. while (i--) {
  15958. const node = nodes[i];
  15959. if (node.name === 'a' && node.attr('target') === '_blank') {
  15960. node.attr('rel', addNoOpener(node.attr('rel')));
  15961. }
  15962. }
  15963. }
  15964. });
  15965. if (!settings.allow_html_in_named_anchor) {
  15966. parser.addAttributeFilter('id,name', nodes => {
  15967. let i = nodes.length, sibling, prevSibling, parent, node;
  15968. while (i--) {
  15969. node = nodes[i];
  15970. if (node.name === 'a' && node.firstChild && !node.attr('href')) {
  15971. parent = node.parent;
  15972. sibling = node.lastChild;
  15973. while (sibling && parent) {
  15974. prevSibling = sibling.prev;
  15975. parent.insert(sibling, node);
  15976. sibling = prevSibling;
  15977. }
  15978. }
  15979. }
  15980. });
  15981. }
  15982. if (settings.fix_list_elements) {
  15983. parser.addNodeFilter('ul,ol', nodes => {
  15984. let i = nodes.length, node, parentNode;
  15985. while (i--) {
  15986. node = nodes[i];
  15987. parentNode = node.parent;
  15988. if (parentNode && (parentNode.name === 'ul' || parentNode.name === 'ol')) {
  15989. if (node.prev && node.prev.name === 'li') {
  15990. node.prev.append(node);
  15991. } else {
  15992. const li = new AstNode('li', 1);
  15993. li.attr('style', 'list-style-type: none');
  15994. node.wrap(li);
  15995. }
  15996. }
  15997. }
  15998. });
  15999. }
  16000. const validClasses = schema.getValidClasses();
  16001. if (settings.validate && validClasses) {
  16002. parser.addAttributeFilter('class', nodes => {
  16003. var _a;
  16004. let i = nodes.length;
  16005. while (i--) {
  16006. const node = nodes[i];
  16007. const clazz = (_a = node.attr('class')) !== null && _a !== void 0 ? _a : '';
  16008. const classList = Tools.explode(clazz, ' ');
  16009. let classValue = '';
  16010. for (let ci = 0; ci < classList.length; ci++) {
  16011. const className = classList[ci];
  16012. let valid = false;
  16013. let validClassesMap = validClasses['*'];
  16014. if (validClassesMap && validClassesMap[className]) {
  16015. valid = true;
  16016. }
  16017. validClassesMap = validClasses[node.name];
  16018. if (!valid && validClassesMap && validClassesMap[className]) {
  16019. valid = true;
  16020. }
  16021. if (valid) {
  16022. if (classValue) {
  16023. classValue += ' ';
  16024. }
  16025. classValue += className;
  16026. }
  16027. }
  16028. if (!classValue.length) {
  16029. classValue = null;
  16030. }
  16031. node.attr('class', classValue);
  16032. }
  16033. });
  16034. }
  16035. registerBase64ImageFilter(parser, settings);
  16036. };
  16037. const each$4 = Tools.each, trim = Tools.trim;
  16038. const queryParts = [
  16039. 'source',
  16040. 'protocol',
  16041. 'authority',
  16042. 'userInfo',
  16043. 'user',
  16044. 'password',
  16045. 'host',
  16046. 'port',
  16047. 'relative',
  16048. 'path',
  16049. 'directory',
  16050. 'file',
  16051. 'query',
  16052. 'anchor'
  16053. ];
  16054. const DEFAULT_PORTS = {
  16055. ftp: 21,
  16056. http: 80,
  16057. https: 443,
  16058. mailto: 25
  16059. };
  16060. const safeSvgDataUrlElements = [
  16061. 'img',
  16062. 'video'
  16063. ];
  16064. const blockSvgDataUris = (allowSvgDataUrls, tagName) => {
  16065. if (isNonNullable(allowSvgDataUrls)) {
  16066. return !allowSvgDataUrls;
  16067. } else {
  16068. return isNonNullable(tagName) ? !contains$2(safeSvgDataUrlElements, tagName) : true;
  16069. }
  16070. };
  16071. const decodeUri = encodedUri => {
  16072. try {
  16073. return decodeURIComponent(encodedUri);
  16074. } catch (ex) {
  16075. return unescape(encodedUri);
  16076. }
  16077. };
  16078. const isInvalidUri = (settings, uri, tagName) => {
  16079. const decodedUri = decodeUri(uri);
  16080. if (settings.allow_script_urls) {
  16081. return false;
  16082. } else if (/((java|vb)script|mhtml):/i.test(decodedUri)) {
  16083. return true;
  16084. } else if (settings.allow_html_data_urls) {
  16085. return false;
  16086. } else if (/^data:image\//i.test(decodedUri)) {
  16087. return blockSvgDataUris(settings.allow_svg_data_urls, tagName) && /^data:image\/svg\+xml/i.test(decodedUri);
  16088. } else {
  16089. return /^data:/i.test(decodedUri);
  16090. }
  16091. };
  16092. class URI {
  16093. constructor(url, settings = {}) {
  16094. this.path = '';
  16095. this.directory = '';
  16096. url = trim(url);
  16097. this.settings = settings;
  16098. const baseUri = settings.base_uri;
  16099. const self = this;
  16100. if (/^([\w\-]+):([^\/]{2})/i.test(url) || /^\s*#/.test(url)) {
  16101. self.source = url;
  16102. return;
  16103. }
  16104. const isProtocolRelative = url.indexOf('//') === 0;
  16105. if (url.indexOf('/') === 0 && !isProtocolRelative) {
  16106. url = (baseUri ? baseUri.protocol || 'http' : 'http') + '://mce_host' + url;
  16107. }
  16108. if (!/^[\w\-]*:?\/\//.test(url)) {
  16109. const baseUrl = baseUri ? baseUri.path : new URI(document.location.href).directory;
  16110. if ((baseUri === null || baseUri === void 0 ? void 0 : baseUri.protocol) === '') {
  16111. url = '//mce_host' + self.toAbsPath(baseUrl, url);
  16112. } else {
  16113. const match = /([^#?]*)([#?]?.*)/.exec(url);
  16114. if (match) {
  16115. url = (baseUri && baseUri.protocol || 'http') + '://mce_host' + self.toAbsPath(baseUrl, match[1]) + match[2];
  16116. }
  16117. }
  16118. }
  16119. url = url.replace(/@@/g, '(mce_at)');
  16120. const urlMatch = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?(\[[a-zA-Z0-9:.%]+\]|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(url);
  16121. if (urlMatch) {
  16122. each$4(queryParts, (v, i) => {
  16123. let part = urlMatch[i];
  16124. if (part) {
  16125. part = part.replace(/\(mce_at\)/g, '@@');
  16126. }
  16127. self[v] = part;
  16128. });
  16129. }
  16130. if (baseUri) {
  16131. if (!self.protocol) {
  16132. self.protocol = baseUri.protocol;
  16133. }
  16134. if (!self.userInfo) {
  16135. self.userInfo = baseUri.userInfo;
  16136. }
  16137. if (!self.port && self.host === 'mce_host') {
  16138. self.port = baseUri.port;
  16139. }
  16140. if (!self.host || self.host === 'mce_host') {
  16141. self.host = baseUri.host;
  16142. }
  16143. self.source = '';
  16144. }
  16145. if (isProtocolRelative) {
  16146. self.protocol = '';
  16147. }
  16148. }
  16149. static parseDataUri(uri) {
  16150. let type;
  16151. const uriComponents = decodeURIComponent(uri).split(',');
  16152. const matches = /data:([^;]+)/.exec(uriComponents[0]);
  16153. if (matches) {
  16154. type = matches[1];
  16155. }
  16156. return {
  16157. type,
  16158. data: uriComponents[1]
  16159. };
  16160. }
  16161. static isDomSafe(uri, context, options = {}) {
  16162. if (options.allow_script_urls) {
  16163. return true;
  16164. } else {
  16165. const decodedUri = Entities.decode(uri).replace(/[\s\u0000-\u001F]+/g, '');
  16166. return !isInvalidUri(options, decodedUri, context);
  16167. }
  16168. }
  16169. static getDocumentBaseUrl(loc) {
  16170. var _a;
  16171. let baseUrl;
  16172. if (loc.protocol.indexOf('http') !== 0 && loc.protocol !== 'file:') {
  16173. baseUrl = (_a = loc.href) !== null && _a !== void 0 ? _a : '';
  16174. } else {
  16175. baseUrl = loc.protocol + '//' + loc.host + loc.pathname;
  16176. }
  16177. if (/^[^:]+:\/\/\/?[^\/]+\//.test(baseUrl)) {
  16178. baseUrl = baseUrl.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
  16179. if (!/[\/\\]$/.test(baseUrl)) {
  16180. baseUrl += '/';
  16181. }
  16182. }
  16183. return baseUrl;
  16184. }
  16185. setPath(path) {
  16186. const pathMatch = /^(.*?)\/?(\w+)?$/.exec(path);
  16187. if (pathMatch) {
  16188. this.path = pathMatch[0];
  16189. this.directory = pathMatch[1];
  16190. this.file = pathMatch[2];
  16191. }
  16192. this.source = '';
  16193. this.getURI();
  16194. }
  16195. toRelative(uri) {
  16196. if (uri === './') {
  16197. return uri;
  16198. }
  16199. const relativeUri = new URI(uri, { base_uri: this });
  16200. if (relativeUri.host !== 'mce_host' && this.host !== relativeUri.host && relativeUri.host || this.port !== relativeUri.port || this.protocol !== relativeUri.protocol && relativeUri.protocol !== '') {
  16201. return relativeUri.getURI();
  16202. }
  16203. const tu = this.getURI(), uu = relativeUri.getURI();
  16204. if (tu === uu || tu.charAt(tu.length - 1) === '/' && tu.substr(0, tu.length - 1) === uu) {
  16205. return tu;
  16206. }
  16207. let output = this.toRelPath(this.path, relativeUri.path);
  16208. if (relativeUri.query) {
  16209. output += '?' + relativeUri.query;
  16210. }
  16211. if (relativeUri.anchor) {
  16212. output += '#' + relativeUri.anchor;
  16213. }
  16214. return output;
  16215. }
  16216. toAbsolute(uri, noHost) {
  16217. const absoluteUri = new URI(uri, { base_uri: this });
  16218. return absoluteUri.getURI(noHost && this.isSameOrigin(absoluteUri));
  16219. }
  16220. isSameOrigin(uri) {
  16221. if (this.host == uri.host && this.protocol == uri.protocol) {
  16222. if (this.port == uri.port) {
  16223. return true;
  16224. }
  16225. const defaultPort = this.protocol ? DEFAULT_PORTS[this.protocol] : null;
  16226. if (defaultPort && (this.port || defaultPort) == (uri.port || defaultPort)) {
  16227. return true;
  16228. }
  16229. }
  16230. return false;
  16231. }
  16232. toRelPath(base, path) {
  16233. let breakPoint = 0, out = '', i, l;
  16234. const normalizedBase = base.substring(0, base.lastIndexOf('/')).split('/');
  16235. const items = path.split('/');
  16236. if (normalizedBase.length >= items.length) {
  16237. for (i = 0, l = normalizedBase.length; i < l; i++) {
  16238. if (i >= items.length || normalizedBase[i] !== items[i]) {
  16239. breakPoint = i + 1;
  16240. break;
  16241. }
  16242. }
  16243. }
  16244. if (normalizedBase.length < items.length) {
  16245. for (i = 0, l = items.length; i < l; i++) {
  16246. if (i >= normalizedBase.length || normalizedBase[i] !== items[i]) {
  16247. breakPoint = i + 1;
  16248. break;
  16249. }
  16250. }
  16251. }
  16252. if (breakPoint === 1) {
  16253. return path;
  16254. }
  16255. for (i = 0, l = normalizedBase.length - (breakPoint - 1); i < l; i++) {
  16256. out += '../';
  16257. }
  16258. for (i = breakPoint - 1, l = items.length; i < l; i++) {
  16259. if (i !== breakPoint - 1) {
  16260. out += '/' + items[i];
  16261. } else {
  16262. out += items[i];
  16263. }
  16264. }
  16265. return out;
  16266. }
  16267. toAbsPath(base, path) {
  16268. let nb = 0;
  16269. const tr = /\/$/.test(path) ? '/' : '';
  16270. const normalizedBase = base.split('/');
  16271. const normalizedPath = path.split('/');
  16272. const baseParts = [];
  16273. each$4(normalizedBase, k => {
  16274. if (k) {
  16275. baseParts.push(k);
  16276. }
  16277. });
  16278. const pathParts = [];
  16279. for (let i = normalizedPath.length - 1; i >= 0; i--) {
  16280. if (normalizedPath[i].length === 0 || normalizedPath[i] === '.') {
  16281. continue;
  16282. }
  16283. if (normalizedPath[i] === '..') {
  16284. nb++;
  16285. continue;
  16286. }
  16287. if (nb > 0) {
  16288. nb--;
  16289. continue;
  16290. }
  16291. pathParts.push(normalizedPath[i]);
  16292. }
  16293. const i = baseParts.length - nb;
  16294. let outPath;
  16295. if (i <= 0) {
  16296. outPath = reverse(pathParts).join('/');
  16297. } else {
  16298. outPath = baseParts.slice(0, i).join('/') + '/' + reverse(pathParts).join('/');
  16299. }
  16300. if (outPath.indexOf('/') !== 0) {
  16301. outPath = '/' + outPath;
  16302. }
  16303. if (tr && outPath.lastIndexOf('/') !== outPath.length - 1) {
  16304. outPath += tr;
  16305. }
  16306. return outPath;
  16307. }
  16308. getURI(noProtoHost = false) {
  16309. let s;
  16310. if (!this.source || noProtoHost) {
  16311. s = '';
  16312. if (!noProtoHost) {
  16313. if (this.protocol) {
  16314. s += this.protocol + '://';
  16315. } else {
  16316. s += '//';
  16317. }
  16318. if (this.userInfo) {
  16319. s += this.userInfo + '@';
  16320. }
  16321. if (this.host) {
  16322. s += this.host;
  16323. }
  16324. if (this.port) {
  16325. s += ':' + this.port;
  16326. }
  16327. }
  16328. if (this.path) {
  16329. s += this.path;
  16330. }
  16331. if (this.query) {
  16332. s += '?' + this.query;
  16333. }
  16334. if (this.anchor) {
  16335. s += '#' + this.anchor;
  16336. }
  16337. this.source = s;
  16338. }
  16339. return this.source;
  16340. }
  16341. }
  16342. const makeMap = Tools.makeMap, extend$1 = Tools.extend;
  16343. const basePurifyConfig = {
  16344. IN_PLACE: true,
  16345. ALLOW_UNKNOWN_PROTOCOLS: true,
  16346. ALLOWED_TAGS: [
  16347. '#comment',
  16348. '#cdata-section',
  16349. 'body'
  16350. ],
  16351. ALLOWED_ATTR: []
  16352. };
  16353. const filteredUrlAttrs = Tools.makeMap('src,href,data,background,action,formaction,poster,xlink:href');
  16354. const internalElementAttr = 'data-mce-type';
  16355. const getPurifyConfig = (settings, mimeType) => {
  16356. const config = { ...basePurifyConfig };
  16357. config.PARSER_MEDIA_TYPE = mimeType;
  16358. if (settings.allow_script_urls) {
  16359. config.ALLOWED_URI_REGEXP = /.*/;
  16360. } else if (settings.allow_html_data_urls) {
  16361. config.ALLOWED_URI_REGEXP = /^(?!(\w+script|mhtml):)/i;
  16362. }
  16363. return config;
  16364. };
  16365. const setupPurify = (settings, schema) => {
  16366. const purify$1 = purify();
  16367. const specialElements = schema.getSpecialElements();
  16368. const validate = settings.validate;
  16369. let uid = 0;
  16370. purify$1.addHook('uponSanitizeElement', (ele, evt) => {
  16371. var _a, _b, _c;
  16372. if (ele.nodeType === COMMENT && !settings.allow_conditional_comments && /^\[if/i.test((_a = ele.nodeValue) !== null && _a !== void 0 ? _a : '')) {
  16373. ele.nodeValue = ' ' + ele.nodeValue;
  16374. }
  16375. const tagName = evt.tagName;
  16376. if (ele.nodeType !== ELEMENT || tagName === 'body') {
  16377. return;
  16378. }
  16379. const element = SugarElement.fromDom(ele);
  16380. const lcTagName = tagName.toLowerCase();
  16381. const isInternalElement = has$1(element, internalElementAttr);
  16382. const bogus = get$9(element, 'data-mce-bogus');
  16383. if (!isInternalElement && isString(bogus)) {
  16384. if (bogus === 'all') {
  16385. remove$6(element);
  16386. } else {
  16387. unwrap(element);
  16388. }
  16389. return;
  16390. }
  16391. const rule = schema.getElementRule(lcTagName);
  16392. if (validate && !rule) {
  16393. if (has$2(specialElements, lcTagName)) {
  16394. remove$6(element);
  16395. } else {
  16396. unwrap(element);
  16397. }
  16398. return;
  16399. } else {
  16400. evt.allowedTags[tagName] = true;
  16401. }
  16402. if (validate && rule && !isInternalElement) {
  16403. each$e((_b = rule.attributesForced) !== null && _b !== void 0 ? _b : [], attr => {
  16404. set$2(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
  16405. });
  16406. each$e((_c = rule.attributesDefault) !== null && _c !== void 0 ? _c : [], attr => {
  16407. if (!has$1(element, attr.name)) {
  16408. set$2(element, attr.name, attr.value === '{$uid}' ? `mce_${ uid++ }` : attr.value);
  16409. }
  16410. });
  16411. if (rule.attributesRequired && !exists(rule.attributesRequired, attr => has$1(element, attr))) {
  16412. unwrap(element);
  16413. return;
  16414. }
  16415. if (rule.removeEmptyAttrs && hasNone(element)) {
  16416. unwrap(element);
  16417. return;
  16418. }
  16419. if (rule.outputName && rule.outputName !== lcTagName) {
  16420. mutate(element, rule.outputName);
  16421. }
  16422. }
  16423. });
  16424. purify$1.addHook('uponSanitizeAttribute', (ele, evt) => {
  16425. const tagName = ele.tagName.toLowerCase();
  16426. const {attrName, attrValue} = evt;
  16427. evt.keepAttr = !validate || schema.isValid(tagName, attrName) || startsWith(attrName, 'data-') || startsWith(attrName, 'aria-');
  16428. if (attrName in filteredUrlAttrs && isInvalidUri(settings, attrValue, tagName)) {
  16429. evt.keepAttr = false;
  16430. }
  16431. if (evt.keepAttr) {
  16432. evt.allowedAttributes[attrName] = true;
  16433. if (attrName in schema.getBoolAttrs()) {
  16434. evt.attrValue = attrName;
  16435. }
  16436. if (settings.allow_svg_data_urls && startsWith(attrValue, 'data:image/svg+xml')) {
  16437. evt.forceKeepAttr = true;
  16438. }
  16439. } else if (ele.hasAttribute(internalElementAttr) && (attrName === 'id' || attrName === 'class' || attrName === 'style')) {
  16440. evt.forceKeepAttr = true;
  16441. }
  16442. });
  16443. return purify$1;
  16444. };
  16445. const transferChildren = (parent, nativeParent, specialElements) => {
  16446. const parentName = parent.name;
  16447. const isSpecial = parentName in specialElements && parentName !== 'title' && parentName !== 'textarea';
  16448. const childNodes = nativeParent.childNodes;
  16449. for (let ni = 0, nl = childNodes.length; ni < nl; ni++) {
  16450. const nativeChild = childNodes[ni];
  16451. const child = new AstNode(nativeChild.nodeName.toLowerCase(), nativeChild.nodeType);
  16452. if (isElement$6(nativeChild)) {
  16453. const attributes = nativeChild.attributes;
  16454. for (let ai = 0, al = attributes.length; ai < al; ai++) {
  16455. const attr = attributes[ai];
  16456. child.attr(attr.name, attr.value);
  16457. }
  16458. } else if (isText$a(nativeChild)) {
  16459. child.value = nativeChild.data;
  16460. if (isSpecial) {
  16461. child.raw = true;
  16462. }
  16463. } else if (isComment(nativeChild) || isCData(nativeChild) || isPi(nativeChild)) {
  16464. child.value = nativeChild.data;
  16465. }
  16466. transferChildren(child, nativeChild, specialElements);
  16467. parent.append(child);
  16468. }
  16469. };
  16470. const walkTree = (root, preprocessors, postprocessors) => {
  16471. const traverseOrder = [];
  16472. for (let node = root, lastNode = node; node; lastNode = node, node = node.walk()) {
  16473. const tempNode = node;
  16474. each$e(preprocessors, preprocess => preprocess(tempNode));
  16475. if (isNullable(tempNode.parent) && tempNode !== root) {
  16476. node = lastNode;
  16477. } else {
  16478. traverseOrder.push(tempNode);
  16479. }
  16480. }
  16481. for (let i = traverseOrder.length - 1; i >= 0; i--) {
  16482. const node = traverseOrder[i];
  16483. each$e(postprocessors, postprocess => postprocess(node));
  16484. }
  16485. };
  16486. const whitespaceCleaner = (root, schema, settings, args) => {
  16487. const validate = settings.validate;
  16488. const nonEmptyElements = schema.getNonEmptyElements();
  16489. const whitespaceElements = schema.getWhitespaceElements();
  16490. const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
  16491. const textRootBlockElements = getTextRootBlockElements(schema);
  16492. const allWhiteSpaceRegExp = /[ \t\r\n]+/g;
  16493. const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
  16494. const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
  16495. const hasWhitespaceParent = node => {
  16496. let tempNode = node.parent;
  16497. while (isNonNullable(tempNode)) {
  16498. if (tempNode.name in whitespaceElements) {
  16499. return true;
  16500. } else {
  16501. tempNode = tempNode.parent;
  16502. }
  16503. }
  16504. return false;
  16505. };
  16506. const isTextRootBlockEmpty = node => {
  16507. let tempNode = node;
  16508. while (isNonNullable(tempNode)) {
  16509. if (tempNode.name in textRootBlockElements) {
  16510. return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode);
  16511. } else {
  16512. tempNode = tempNode.parent;
  16513. }
  16514. }
  16515. return false;
  16516. };
  16517. const isBlock = node => node.name in blockElements && !isTransparentAstInline(schema, node);
  16518. const isAtEdgeOfBlock = (node, start) => {
  16519. const neighbour = start ? node.prev : node.next;
  16520. if (isNonNullable(neighbour) || isNullable(node.parent)) {
  16521. return false;
  16522. }
  16523. return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true);
  16524. };
  16525. const preprocess = node => {
  16526. var _a;
  16527. if (node.type === 3) {
  16528. if (!hasWhitespaceParent(node)) {
  16529. let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
  16530. text = text.replace(allWhiteSpaceRegExp, ' ');
  16531. if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) {
  16532. text = text.replace(startWhiteSpaceRegExp, '');
  16533. }
  16534. if (text.length === 0) {
  16535. node.remove();
  16536. } else {
  16537. node.value = text;
  16538. }
  16539. }
  16540. }
  16541. };
  16542. const postprocess = node => {
  16543. var _a;
  16544. if (node.type === 1) {
  16545. const elementRule = schema.getElementRule(node.name);
  16546. if (validate && elementRule) {
  16547. const isNodeEmpty = isEmpty(schema, nonEmptyElements, whitespaceElements, node);
  16548. if (elementRule.paddInEmptyBlock && isNodeEmpty && isTextRootBlockEmpty(node)) {
  16549. paddEmptyNode(args, isBlock, node);
  16550. } else if (elementRule.removeEmpty && isNodeEmpty) {
  16551. if (isBlock(node)) {
  16552. node.remove();
  16553. } else {
  16554. node.unwrap();
  16555. }
  16556. } else if (elementRule.paddEmpty && (isNodeEmpty || isPaddedWithNbsp(node))) {
  16557. paddEmptyNode(args, isBlock, node);
  16558. }
  16559. }
  16560. } else if (node.type === 3) {
  16561. if (!hasWhitespaceParent(node)) {
  16562. let text = (_a = node.value) !== null && _a !== void 0 ? _a : '';
  16563. if (node.next && isBlock(node.next) || isAtEdgeOfBlock(node, false)) {
  16564. text = text.replace(endWhiteSpaceRegExp, '');
  16565. }
  16566. if (text.length === 0) {
  16567. node.remove();
  16568. } else {
  16569. node.value = text;
  16570. }
  16571. }
  16572. }
  16573. };
  16574. return [
  16575. preprocess,
  16576. postprocess
  16577. ];
  16578. };
  16579. const getRootBlockName = (settings, args) => {
  16580. var _a;
  16581. const name = (_a = args.forced_root_block) !== null && _a !== void 0 ? _a : settings.forced_root_block;
  16582. if (name === false) {
  16583. return '';
  16584. } else if (name === true) {
  16585. return 'p';
  16586. } else {
  16587. return name;
  16588. }
  16589. };
  16590. const DomParser = (settings = {}, schema = Schema()) => {
  16591. const nodeFilterRegistry = create$7();
  16592. const attributeFilterRegistry = create$7();
  16593. const defaultedSettings = {
  16594. validate: true,
  16595. root_name: 'body',
  16596. ...settings
  16597. };
  16598. const parser = new DOMParser();
  16599. const purify = setupPurify(defaultedSettings, schema);
  16600. const parseAndSanitizeWithContext = (html, rootName, format = 'html') => {
  16601. const mimeType = format === 'xhtml' ? 'application/xhtml+xml' : 'text/html';
  16602. const isSpecialRoot = has$2(schema.getSpecialElements(), rootName.toLowerCase());
  16603. const content = isSpecialRoot ? `<${ rootName }>${ html }</${ rootName }>` : html;
  16604. const wrappedHtml = format === 'xhtml' ? `<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>${ content }</body></html>` : `<body>${ content }</body>`;
  16605. const body = parser.parseFromString(wrappedHtml, mimeType).body;
  16606. purify.sanitize(body, getPurifyConfig(defaultedSettings, mimeType));
  16607. purify.removed = [];
  16608. return isSpecialRoot ? body.firstChild : body;
  16609. };
  16610. const addNodeFilter = nodeFilterRegistry.addFilter;
  16611. const getNodeFilters = nodeFilterRegistry.getFilters;
  16612. const removeNodeFilter = nodeFilterRegistry.removeFilter;
  16613. const addAttributeFilter = attributeFilterRegistry.addFilter;
  16614. const getAttributeFilters = attributeFilterRegistry.getFilters;
  16615. const removeAttributeFilter = attributeFilterRegistry.removeFilter;
  16616. const findInvalidChildren = (node, invalidChildren) => {
  16617. if (isInvalid(schema, node)) {
  16618. invalidChildren.push(node);
  16619. }
  16620. };
  16621. const isWrappableNode = (blockElements, node) => {
  16622. const isInternalElement = isString(node.attr(internalElementAttr));
  16623. const isInlineElement = node.type === 1 && (!has$2(blockElements, node.name) && !isTransparentAstBlock(schema, node));
  16624. return node.type === 3 || isInlineElement && !isInternalElement;
  16625. };
  16626. const addRootBlocks = (rootNode, rootBlockName) => {
  16627. const blockElements = extend$1(makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
  16628. const startWhiteSpaceRegExp = /^[ \t\r\n]+/;
  16629. const endWhiteSpaceRegExp = /[ \t\r\n]+$/;
  16630. let node = rootNode.firstChild, rootBlockNode = null;
  16631. const trim = rootBlock => {
  16632. var _a, _b;
  16633. if (rootBlock) {
  16634. node = rootBlock.firstChild;
  16635. if (node && node.type === 3) {
  16636. node.value = (_a = node.value) === null || _a === void 0 ? void 0 : _a.replace(startWhiteSpaceRegExp, '');
  16637. }
  16638. node = rootBlock.lastChild;
  16639. if (node && node.type === 3) {
  16640. node.value = (_b = node.value) === null || _b === void 0 ? void 0 : _b.replace(endWhiteSpaceRegExp, '');
  16641. }
  16642. }
  16643. };
  16644. if (!schema.isValidChild(rootNode.name, rootBlockName.toLowerCase())) {
  16645. return;
  16646. }
  16647. while (node) {
  16648. const next = node.next;
  16649. if (isWrappableNode(blockElements, node)) {
  16650. if (!rootBlockNode) {
  16651. rootBlockNode = new AstNode(rootBlockName, 1);
  16652. rootBlockNode.attr(defaultedSettings.forced_root_block_attrs);
  16653. rootNode.insert(rootBlockNode, node);
  16654. rootBlockNode.append(node);
  16655. } else {
  16656. rootBlockNode.append(node);
  16657. }
  16658. } else {
  16659. trim(rootBlockNode);
  16660. rootBlockNode = null;
  16661. }
  16662. node = next;
  16663. }
  16664. trim(rootBlockNode);
  16665. };
  16666. const parse = (html, args = {}) => {
  16667. var _a;
  16668. const validate = defaultedSettings.validate;
  16669. const rootName = (_a = args.context) !== null && _a !== void 0 ? _a : defaultedSettings.root_name;
  16670. const element = parseAndSanitizeWithContext(html, rootName, args.format);
  16671. updateChildren(schema, element);
  16672. const rootNode = new AstNode(rootName, 11);
  16673. transferChildren(rootNode, element, schema.getSpecialElements());
  16674. element.innerHTML = '';
  16675. const [whitespacePre, whitespacePost] = whitespaceCleaner(rootNode, schema, defaultedSettings, args);
  16676. const invalidChildren = [];
  16677. const invalidFinder = validate ? node => findInvalidChildren(node, invalidChildren) : noop;
  16678. const matches = {
  16679. nodes: {},
  16680. attributes: {}
  16681. };
  16682. const matchFinder = node => matchNode$1(getNodeFilters(), getAttributeFilters(), node, matches);
  16683. walkTree(rootNode, [
  16684. whitespacePre,
  16685. matchFinder
  16686. ], [
  16687. whitespacePost,
  16688. invalidFinder
  16689. ]);
  16690. invalidChildren.reverse();
  16691. if (validate && invalidChildren.length > 0) {
  16692. if (args.context) {
  16693. const {
  16694. pass: topLevelChildren,
  16695. fail: otherChildren
  16696. } = partition$2(invalidChildren, child => child.parent === rootNode);
  16697. cleanInvalidNodes(otherChildren, schema, matchFinder);
  16698. args.invalid = topLevelChildren.length > 0;
  16699. } else {
  16700. cleanInvalidNodes(invalidChildren, schema, matchFinder);
  16701. }
  16702. }
  16703. const rootBlockName = getRootBlockName(defaultedSettings, args);
  16704. if (rootBlockName && (rootNode.name === 'body' || args.isRootContent)) {
  16705. addRootBlocks(rootNode, rootBlockName);
  16706. }
  16707. if (!args.invalid) {
  16708. runFilters(matches, args);
  16709. }
  16710. return rootNode;
  16711. };
  16712. const exports = {
  16713. schema,
  16714. addAttributeFilter,
  16715. getAttributeFilters,
  16716. removeAttributeFilter,
  16717. addNodeFilter,
  16718. getNodeFilters,
  16719. removeNodeFilter,
  16720. parse
  16721. };
  16722. register$4(exports, defaultedSettings);
  16723. register$5(exports, defaultedSettings, schema);
  16724. return exports;
  16725. };
  16726. const serializeContent = content => isTreeNode(content) ? HtmlSerializer({ validate: false }).serialize(content) : content;
  16727. const withSerializedContent = (content, fireEvent) => {
  16728. const serializedContent = serializeContent(content);
  16729. const eventArgs = fireEvent(serializedContent);
  16730. if (eventArgs.isDefaultPrevented()) {
  16731. return eventArgs;
  16732. } else if (isTreeNode(content)) {
  16733. if (eventArgs.content !== serializedContent) {
  16734. const rootNode = DomParser({
  16735. validate: false,
  16736. forced_root_block: false
  16737. }).parse(eventArgs.content, { context: content.name });
  16738. return {
  16739. ...eventArgs,
  16740. content: rootNode
  16741. };
  16742. } else {
  16743. return {
  16744. ...eventArgs,
  16745. content
  16746. };
  16747. }
  16748. } else {
  16749. return eventArgs;
  16750. }
  16751. };
  16752. const preProcessGetContent = (editor, args) => {
  16753. if (args.no_events) {
  16754. return Result.value(args);
  16755. } else {
  16756. const eventArgs = fireBeforeGetContent(editor, args);
  16757. if (eventArgs.isDefaultPrevented()) {
  16758. return Result.error(fireGetContent(editor, {
  16759. content: '',
  16760. ...eventArgs
  16761. }).content);
  16762. } else {
  16763. return Result.value(eventArgs);
  16764. }
  16765. }
  16766. };
  16767. const postProcessGetContent = (editor, content, args) => {
  16768. if (args.no_events) {
  16769. return content;
  16770. } else {
  16771. const processedEventArgs = withSerializedContent(content, c => fireGetContent(editor, {
  16772. ...args,
  16773. content: c
  16774. }));
  16775. return processedEventArgs.content;
  16776. }
  16777. };
  16778. const preProcessSetContent = (editor, args) => {
  16779. if (args.no_events) {
  16780. return Result.value(args);
  16781. } else {
  16782. const processedEventArgs = withSerializedContent(args.content, content => fireBeforeSetContent(editor, {
  16783. ...args,
  16784. content
  16785. }));
  16786. if (processedEventArgs.isDefaultPrevented()) {
  16787. fireSetContent(editor, processedEventArgs);
  16788. return Result.error(undefined);
  16789. } else {
  16790. return Result.value(processedEventArgs);
  16791. }
  16792. }
  16793. };
  16794. const postProcessSetContent = (editor, content, args) => {
  16795. if (!args.no_events) {
  16796. fireSetContent(editor, {
  16797. ...args,
  16798. content
  16799. });
  16800. }
  16801. };
  16802. const tableModel = (element, width, rows) => ({
  16803. element,
  16804. width,
  16805. rows
  16806. });
  16807. const tableRow = (element, cells) => ({
  16808. element,
  16809. cells
  16810. });
  16811. const cellPosition = (x, y) => ({
  16812. x,
  16813. y
  16814. });
  16815. const getSpan = (td, key) => {
  16816. return getOpt(td, key).bind(toInt).getOr(1);
  16817. };
  16818. const fillout = (table, x, y, tr, td) => {
  16819. const rowspan = getSpan(td, 'rowspan');
  16820. const colspan = getSpan(td, 'colspan');
  16821. const rows = table.rows;
  16822. for (let y2 = y; y2 < y + rowspan; y2++) {
  16823. if (!rows[y2]) {
  16824. rows[y2] = tableRow(deep$1(tr), []);
  16825. }
  16826. for (let x2 = x; x2 < x + colspan; x2++) {
  16827. const cells = rows[y2].cells;
  16828. cells[x2] = y2 === y && x2 === x ? td : shallow$1(td);
  16829. }
  16830. }
  16831. };
  16832. const cellExists = (table, x, y) => {
  16833. const rows = table.rows;
  16834. const cells = rows[y] ? rows[y].cells : [];
  16835. return !!cells[x];
  16836. };
  16837. const skipCellsX = (table, x, y) => {
  16838. while (cellExists(table, x, y)) {
  16839. x++;
  16840. }
  16841. return x;
  16842. };
  16843. const getWidth = rows => {
  16844. return foldl(rows, (acc, row) => {
  16845. return row.cells.length > acc ? row.cells.length : acc;
  16846. }, 0);
  16847. };
  16848. const findElementPos = (table, element) => {
  16849. const rows = table.rows;
  16850. for (let y = 0; y < rows.length; y++) {
  16851. const cells = rows[y].cells;
  16852. for (let x = 0; x < cells.length; x++) {
  16853. if (eq(cells[x], element)) {
  16854. return Optional.some(cellPosition(x, y));
  16855. }
  16856. }
  16857. }
  16858. return Optional.none();
  16859. };
  16860. const extractRows = (table, sx, sy, ex, ey) => {
  16861. const newRows = [];
  16862. const rows = table.rows;
  16863. for (let y = sy; y <= ey; y++) {
  16864. const cells = rows[y].cells;
  16865. const slice = sx < ex ? cells.slice(sx, ex + 1) : cells.slice(ex, sx + 1);
  16866. newRows.push(tableRow(rows[y].element, slice));
  16867. }
  16868. return newRows;
  16869. };
  16870. const subTable = (table, startPos, endPos) => {
  16871. const sx = startPos.x, sy = startPos.y;
  16872. const ex = endPos.x, ey = endPos.y;
  16873. const newRows = sy < ey ? extractRows(table, sx, sy, ex, ey) : extractRows(table, sx, ey, ex, sy);
  16874. return tableModel(table.element, getWidth(newRows), newRows);
  16875. };
  16876. const createDomTable = (table, rows) => {
  16877. const tableElement = shallow$1(table.element);
  16878. const tableBody = SugarElement.fromTag('tbody');
  16879. append(tableBody, rows);
  16880. append$1(tableElement, tableBody);
  16881. return tableElement;
  16882. };
  16883. const modelRowsToDomRows = table => {
  16884. return map$3(table.rows, row => {
  16885. const cells = map$3(row.cells, cell => {
  16886. const td = deep$1(cell);
  16887. remove$b(td, 'colspan');
  16888. remove$b(td, 'rowspan');
  16889. return td;
  16890. });
  16891. const tr = shallow$1(row.element);
  16892. append(tr, cells);
  16893. return tr;
  16894. });
  16895. };
  16896. const fromDom = tableElm => {
  16897. const table = tableModel(shallow$1(tableElm), 0, []);
  16898. each$e(descendants(tableElm, 'tr'), (tr, y) => {
  16899. each$e(descendants(tr, 'td,th'), (td, x) => {
  16900. fillout(table, skipCellsX(table, x, y), y, tr, td);
  16901. });
  16902. });
  16903. return tableModel(table.element, getWidth(table.rows), table.rows);
  16904. };
  16905. const toDom = table => {
  16906. return createDomTable(table, modelRowsToDomRows(table));
  16907. };
  16908. const subsection = (table, startElement, endElement) => {
  16909. return findElementPos(table, startElement).bind(startPos => {
  16910. return findElementPos(table, endElement).map(endPos => {
  16911. return subTable(table, startPos, endPos);
  16912. });
  16913. });
  16914. };
  16915. const findParentListContainer = parents => find$2(parents, elm => name(elm) === 'ul' || name(elm) === 'ol');
  16916. const getFullySelectedListWrappers = (parents, rng) => find$2(parents, elm => name(elm) === 'li' && hasAllContentsSelected(elm, rng)).fold(constant([]), _li => findParentListContainer(parents).map(listCont => {
  16917. const listElm = SugarElement.fromTag(name(listCont));
  16918. const listStyles = filter$4(getAllRaw(listCont), (_style, name) => startsWith(name, 'list-style'));
  16919. setAll(listElm, listStyles);
  16920. return [
  16921. SugarElement.fromTag('li'),
  16922. listElm
  16923. ];
  16924. }).getOr([]));
  16925. const wrap = (innerElm, elms) => {
  16926. const wrapped = foldl(elms, (acc, elm) => {
  16927. append$1(elm, acc);
  16928. return elm;
  16929. }, innerElm);
  16930. return elms.length > 0 ? fromElements([wrapped]) : wrapped;
  16931. };
  16932. const directListWrappers = commonAnchorContainer => {
  16933. if (isListItem$1(commonAnchorContainer)) {
  16934. return parent(commonAnchorContainer).filter(isList).fold(constant([]), listElm => [
  16935. commonAnchorContainer,
  16936. listElm
  16937. ]);
  16938. } else {
  16939. return isList(commonAnchorContainer) ? [commonAnchorContainer] : [];
  16940. }
  16941. };
  16942. const getWrapElements = (rootNode, rng) => {
  16943. const commonAnchorContainer = SugarElement.fromDom(rng.commonAncestorContainer);
  16944. const parents = parentsAndSelf(commonAnchorContainer, rootNode);
  16945. const wrapElements = filter$5(parents, isWrapElement);
  16946. const listWrappers = getFullySelectedListWrappers(parents, rng);
  16947. const allWrappers = wrapElements.concat(listWrappers.length ? listWrappers : directListWrappers(commonAnchorContainer));
  16948. return map$3(allWrappers, shallow$1);
  16949. };
  16950. const emptyFragment = () => fromElements([]);
  16951. const getFragmentFromRange = (rootNode, rng) => wrap(SugarElement.fromDom(rng.cloneContents()), getWrapElements(rootNode, rng));
  16952. const getParentTable = (rootElm, cell) => ancestor$2(cell, 'table', curry(eq, rootElm));
  16953. const getTableFragment = (rootNode, selectedTableCells) => getParentTable(rootNode, selectedTableCells[0]).bind(tableElm => {
  16954. const firstCell = selectedTableCells[0];
  16955. const lastCell = selectedTableCells[selectedTableCells.length - 1];
  16956. const fullTableModel = fromDom(tableElm);
  16957. return subsection(fullTableModel, firstCell, lastCell).map(sectionedTableModel => fromElements([toDom(sectionedTableModel)]));
  16958. }).getOrThunk(emptyFragment);
  16959. const getSelectionFragment = (rootNode, ranges) => ranges.length > 0 && ranges[0].collapsed ? emptyFragment() : getFragmentFromRange(rootNode, ranges[0]);
  16960. const read$3 = (rootNode, ranges) => {
  16961. const selectedCells = getCellsFromElementOrRanges(ranges, rootNode);
  16962. return selectedCells.length > 0 ? getTableFragment(rootNode, selectedCells) : getSelectionFragment(rootNode, ranges);
  16963. };
  16964. const isCollapsibleWhitespace = (text, index) => index >= 0 && index < text.length && isWhiteSpace(text.charAt(index));
  16965. const getInnerText = bin => {
  16966. return trim$1(bin.innerText);
  16967. };
  16968. const getContextNodeName = parentBlockOpt => parentBlockOpt.map(block => block.nodeName).getOr('div').toLowerCase();
  16969. const getTextContent = editor => Optional.from(editor.selection.getRng()).map(rng => {
  16970. var _a;
  16971. const parentBlockOpt = Optional.from(editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock));
  16972. const body = editor.getBody();
  16973. const contextNodeName = getContextNodeName(parentBlockOpt);
  16974. const rangeContentClone = SugarElement.fromDom(rng.cloneContents());
  16975. cleanupBogusElements(rangeContentClone);
  16976. cleanupInputNames(rangeContentClone);
  16977. const bin = editor.dom.add(body, contextNodeName, {
  16978. 'data-mce-bogus': 'all',
  16979. 'style': 'overflow: hidden; opacity: 0;'
  16980. }, rangeContentClone.dom);
  16981. const text = getInnerText(bin);
  16982. const nonRenderedText = trim$1((_a = bin.textContent) !== null && _a !== void 0 ? _a : '');
  16983. editor.dom.remove(bin);
  16984. if (isCollapsibleWhitespace(nonRenderedText, 0) || isCollapsibleWhitespace(nonRenderedText, nonRenderedText.length - 1)) {
  16985. const parentBlock = parentBlockOpt.getOr(body);
  16986. const parentBlockText = getInnerText(parentBlock);
  16987. const textIndex = parentBlockText.indexOf(text);
  16988. if (textIndex === -1) {
  16989. return text;
  16990. } else {
  16991. const hasProceedingSpace = isCollapsibleWhitespace(parentBlockText, textIndex - 1);
  16992. const hasTrailingSpace = isCollapsibleWhitespace(parentBlockText, textIndex + text.length);
  16993. return (hasProceedingSpace ? ' ' : '') + text + (hasTrailingSpace ? ' ' : '');
  16994. }
  16995. } else {
  16996. return text;
  16997. }
  16998. }).getOr('');
  16999. const getSerializedContent = (editor, args) => {
  17000. const rng = editor.selection.getRng(), tmpElm = editor.dom.create('body');
  17001. const sel = editor.selection.getSel();
  17002. const ranges = processRanges(editor, getRanges$1(sel));
  17003. const fragment = args.contextual ? read$3(SugarElement.fromDom(editor.getBody()), ranges).dom : rng.cloneContents();
  17004. if (fragment) {
  17005. tmpElm.appendChild(fragment);
  17006. }
  17007. return editor.selection.serializer.serialize(tmpElm, args);
  17008. };
  17009. const extractSelectedContent = (editor, args) => {
  17010. if (args.format === 'text') {
  17011. return getTextContent(editor);
  17012. } else {
  17013. const content = getSerializedContent(editor, args);
  17014. if (args.format === 'tree') {
  17015. return content;
  17016. } else {
  17017. return editor.selection.isCollapsed() ? '' : content;
  17018. }
  17019. }
  17020. };
  17021. const setupArgs$3 = (args, format) => ({
  17022. ...args,
  17023. format,
  17024. get: true,
  17025. selection: true,
  17026. getInner: true
  17027. });
  17028. const getSelectedContentInternal = (editor, format, args = {}) => {
  17029. const defaultedArgs = setupArgs$3(args, format);
  17030. return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
  17031. const content = extractSelectedContent(editor, updatedArgs);
  17032. return postProcessGetContent(editor, content, updatedArgs);
  17033. });
  17034. };
  17035. const KEEP = 0, INSERT = 1, DELETE = 2;
  17036. const diff = (left, right) => {
  17037. const size = left.length + right.length + 2;
  17038. const vDown = new Array(size);
  17039. const vUp = new Array(size);
  17040. const snake = (start, end, diag) => {
  17041. return {
  17042. start,
  17043. end,
  17044. diag
  17045. };
  17046. };
  17047. const buildScript = (start1, end1, start2, end2, script) => {
  17048. const middle = getMiddleSnake(start1, end1, start2, end2);
  17049. if (middle === null || middle.start === end1 && middle.diag === end1 - end2 || middle.end === start1 && middle.diag === start1 - start2) {
  17050. let i = start1;
  17051. let j = start2;
  17052. while (i < end1 || j < end2) {
  17053. if (i < end1 && j < end2 && left[i] === right[j]) {
  17054. script.push([
  17055. KEEP,
  17056. left[i]
  17057. ]);
  17058. ++i;
  17059. ++j;
  17060. } else {
  17061. if (end1 - start1 > end2 - start2) {
  17062. script.push([
  17063. DELETE,
  17064. left[i]
  17065. ]);
  17066. ++i;
  17067. } else {
  17068. script.push([
  17069. INSERT,
  17070. right[j]
  17071. ]);
  17072. ++j;
  17073. }
  17074. }
  17075. }
  17076. } else {
  17077. buildScript(start1, middle.start, start2, middle.start - middle.diag, script);
  17078. for (let i2 = middle.start; i2 < middle.end; ++i2) {
  17079. script.push([
  17080. KEEP,
  17081. left[i2]
  17082. ]);
  17083. }
  17084. buildScript(middle.end, end1, middle.end - middle.diag, end2, script);
  17085. }
  17086. };
  17087. const buildSnake = (start, diag, end1, end2) => {
  17088. let end = start;
  17089. while (end - diag < end2 && end < end1 && left[end] === right[end - diag]) {
  17090. ++end;
  17091. }
  17092. return snake(start, end, diag);
  17093. };
  17094. const getMiddleSnake = (start1, end1, start2, end2) => {
  17095. const m = end1 - start1;
  17096. const n = end2 - start2;
  17097. if (m === 0 || n === 0) {
  17098. return null;
  17099. }
  17100. const delta = m - n;
  17101. const sum = n + m;
  17102. const offset = (sum % 2 === 0 ? sum : sum + 1) / 2;
  17103. vDown[1 + offset] = start1;
  17104. vUp[1 + offset] = end1 + 1;
  17105. let d, k, i, x, y;
  17106. for (d = 0; d <= offset; ++d) {
  17107. for (k = -d; k <= d; k += 2) {
  17108. i = k + offset;
  17109. if (k === -d || k !== d && vDown[i - 1] < vDown[i + 1]) {
  17110. vDown[i] = vDown[i + 1];
  17111. } else {
  17112. vDown[i] = vDown[i - 1] + 1;
  17113. }
  17114. x = vDown[i];
  17115. y = x - start1 + start2 - k;
  17116. while (x < end1 && y < end2 && left[x] === right[y]) {
  17117. vDown[i] = ++x;
  17118. ++y;
  17119. }
  17120. if (delta % 2 !== 0 && delta - d <= k && k <= delta + d) {
  17121. if (vUp[i - delta] <= vDown[i]) {
  17122. return buildSnake(vUp[i - delta], k + start1 - start2, end1, end2);
  17123. }
  17124. }
  17125. }
  17126. for (k = delta - d; k <= delta + d; k += 2) {
  17127. i = k + offset - delta;
  17128. if (k === delta - d || k !== delta + d && vUp[i + 1] <= vUp[i - 1]) {
  17129. vUp[i] = vUp[i + 1] - 1;
  17130. } else {
  17131. vUp[i] = vUp[i - 1];
  17132. }
  17133. x = vUp[i] - 1;
  17134. y = x - start1 + start2 - k;
  17135. while (x >= start1 && y >= start2 && left[x] === right[y]) {
  17136. vUp[i] = x--;
  17137. y--;
  17138. }
  17139. if (delta % 2 === 0 && -d <= k && k <= d) {
  17140. if (vUp[i] <= vDown[i + delta]) {
  17141. return buildSnake(vUp[i], k + start1 - start2, end1, end2);
  17142. }
  17143. }
  17144. }
  17145. }
  17146. return null;
  17147. };
  17148. const script = [];
  17149. buildScript(0, left.length, 0, right.length, script);
  17150. return script;
  17151. };
  17152. const getOuterHtml = elm => {
  17153. if (isElement$6(elm)) {
  17154. return elm.outerHTML;
  17155. } else if (isText$a(elm)) {
  17156. return Entities.encodeRaw(elm.data, false);
  17157. } else if (isComment(elm)) {
  17158. return '<!--' + elm.data + '-->';
  17159. }
  17160. return '';
  17161. };
  17162. const createFragment = html => {
  17163. let node;
  17164. const container = document.createElement('div');
  17165. const frag = document.createDocumentFragment();
  17166. if (html) {
  17167. container.innerHTML = html;
  17168. }
  17169. while (node = container.firstChild) {
  17170. frag.appendChild(node);
  17171. }
  17172. return frag;
  17173. };
  17174. const insertAt = (elm, html, index) => {
  17175. const fragment = createFragment(html);
  17176. if (elm.hasChildNodes() && index < elm.childNodes.length) {
  17177. const target = elm.childNodes[index];
  17178. elm.insertBefore(fragment, target);
  17179. } else {
  17180. elm.appendChild(fragment);
  17181. }
  17182. };
  17183. const removeAt = (elm, index) => {
  17184. if (elm.hasChildNodes() && index < elm.childNodes.length) {
  17185. const target = elm.childNodes[index];
  17186. elm.removeChild(target);
  17187. }
  17188. };
  17189. const applyDiff = (diff, elm) => {
  17190. let index = 0;
  17191. each$e(diff, action => {
  17192. if (action[0] === KEEP) {
  17193. index++;
  17194. } else if (action[0] === INSERT) {
  17195. insertAt(elm, action[1], index);
  17196. index++;
  17197. } else if (action[0] === DELETE) {
  17198. removeAt(elm, index);
  17199. }
  17200. });
  17201. };
  17202. const read$2 = elm => {
  17203. return filter$5(map$3(from(elm.childNodes), getOuterHtml), item => {
  17204. return item.length > 0;
  17205. });
  17206. };
  17207. const write = (fragments, elm) => {
  17208. const currentFragments = map$3(from(elm.childNodes), getOuterHtml);
  17209. applyDiff(diff(currentFragments, fragments), elm);
  17210. return elm;
  17211. };
  17212. const lazyTempDocument = cached(() => document.implementation.createHTMLDocument('undo'));
  17213. const hasIframes = html => {
  17214. return html.indexOf('</iframe>') !== -1;
  17215. };
  17216. const createFragmentedLevel = fragments => {
  17217. return {
  17218. type: 'fragmented',
  17219. fragments,
  17220. content: '',
  17221. bookmark: null,
  17222. beforeBookmark: null
  17223. };
  17224. };
  17225. const createCompleteLevel = content => {
  17226. return {
  17227. type: 'complete',
  17228. fragments: null,
  17229. content,
  17230. bookmark: null,
  17231. beforeBookmark: null
  17232. };
  17233. };
  17234. const createFromEditor = editor => {
  17235. const fragments = read$2(editor.getBody());
  17236. const trimmedFragments = bind$3(fragments, html => {
  17237. const trimmed = trimInternal(editor.serializer, html);
  17238. return trimmed.length > 0 ? [trimmed] : [];
  17239. });
  17240. const content = trimmedFragments.join('');
  17241. return hasIframes(content) ? createFragmentedLevel(trimmedFragments) : createCompleteLevel(content);
  17242. };
  17243. const applyToEditor = (editor, level, before) => {
  17244. const bookmark = before ? level.beforeBookmark : level.bookmark;
  17245. if (level.type === 'fragmented') {
  17246. write(level.fragments, editor.getBody());
  17247. } else {
  17248. editor.setContent(level.content, {
  17249. format: 'raw',
  17250. no_selection: isNonNullable(bookmark) && isPathBookmark(bookmark) ? !bookmark.isFakeCaret : true
  17251. });
  17252. }
  17253. if (bookmark) {
  17254. editor.selection.moveToBookmark(bookmark);
  17255. editor.selection.scrollIntoView();
  17256. }
  17257. };
  17258. const getLevelContent = level => {
  17259. return level.type === 'fragmented' ? level.fragments.join('') : level.content;
  17260. };
  17261. const getCleanLevelContent = level => {
  17262. const elm = SugarElement.fromTag('body', lazyTempDocument());
  17263. set(elm, getLevelContent(level));
  17264. each$e(descendants(elm, '*[data-mce-bogus]'), unwrap);
  17265. return get$6(elm);
  17266. };
  17267. const hasEqualContent = (level1, level2) => getLevelContent(level1) === getLevelContent(level2);
  17268. const hasEqualCleanedContent = (level1, level2) => getCleanLevelContent(level1) === getCleanLevelContent(level2);
  17269. const isEq$1 = (level1, level2) => {
  17270. if (!level1 || !level2) {
  17271. return false;
  17272. } else if (hasEqualContent(level1, level2)) {
  17273. return true;
  17274. } else {
  17275. return hasEqualCleanedContent(level1, level2);
  17276. }
  17277. };
  17278. const isUnlocked = locks => locks.get() === 0;
  17279. const setTyping = (undoManager, typing, locks) => {
  17280. if (isUnlocked(locks)) {
  17281. undoManager.typing = typing;
  17282. }
  17283. };
  17284. const endTyping = (undoManager, locks) => {
  17285. if (undoManager.typing) {
  17286. setTyping(undoManager, false, locks);
  17287. undoManager.add();
  17288. }
  17289. };
  17290. const endTypingLevelIgnoreLocks = undoManager => {
  17291. if (undoManager.typing) {
  17292. undoManager.typing = false;
  17293. undoManager.add();
  17294. }
  17295. };
  17296. const beforeChange$1 = (editor, locks, beforeBookmark) => {
  17297. if (isUnlocked(locks)) {
  17298. beforeBookmark.set(getUndoBookmark(editor.selection));
  17299. }
  17300. };
  17301. const addUndoLevel$1 = (editor, undoManager, index, locks, beforeBookmark, level, event) => {
  17302. const currentLevel = createFromEditor(editor);
  17303. const newLevel = Tools.extend(level || {}, currentLevel);
  17304. if (!isUnlocked(locks) || editor.removed) {
  17305. return null;
  17306. }
  17307. const lastLevel = undoManager.data[index.get()];
  17308. if (editor.dispatch('BeforeAddUndo', {
  17309. level: newLevel,
  17310. lastLevel,
  17311. originalEvent: event
  17312. }).isDefaultPrevented()) {
  17313. return null;
  17314. }
  17315. if (lastLevel && isEq$1(lastLevel, newLevel)) {
  17316. return null;
  17317. }
  17318. if (undoManager.data[index.get()]) {
  17319. beforeBookmark.get().each(bm => {
  17320. undoManager.data[index.get()].beforeBookmark = bm;
  17321. });
  17322. }
  17323. const customUndoRedoLevels = getCustomUndoRedoLevels(editor);
  17324. if (customUndoRedoLevels) {
  17325. if (undoManager.data.length > customUndoRedoLevels) {
  17326. for (let i = 0; i < undoManager.data.length - 1; i++) {
  17327. undoManager.data[i] = undoManager.data[i + 1];
  17328. }
  17329. undoManager.data.length--;
  17330. index.set(undoManager.data.length);
  17331. }
  17332. }
  17333. newLevel.bookmark = getUndoBookmark(editor.selection);
  17334. if (index.get() < undoManager.data.length - 1) {
  17335. undoManager.data.length = index.get() + 1;
  17336. }
  17337. undoManager.data.push(newLevel);
  17338. index.set(undoManager.data.length - 1);
  17339. const args = {
  17340. level: newLevel,
  17341. lastLevel,
  17342. originalEvent: event
  17343. };
  17344. if (index.get() > 0) {
  17345. editor.setDirty(true);
  17346. editor.dispatch('AddUndo', args);
  17347. editor.dispatch('change', args);
  17348. } else {
  17349. editor.dispatch('AddUndo', args);
  17350. }
  17351. return newLevel;
  17352. };
  17353. const clear$1 = (editor, undoManager, index) => {
  17354. undoManager.data = [];
  17355. index.set(0);
  17356. undoManager.typing = false;
  17357. editor.dispatch('ClearUndos');
  17358. };
  17359. const extra$1 = (editor, undoManager, index, callback1, callback2) => {
  17360. if (undoManager.transact(callback1)) {
  17361. const bookmark = undoManager.data[index.get()].bookmark;
  17362. const lastLevel = undoManager.data[index.get() - 1];
  17363. applyToEditor(editor, lastLevel, true);
  17364. if (undoManager.transact(callback2)) {
  17365. undoManager.data[index.get() - 1].beforeBookmark = bookmark;
  17366. }
  17367. }
  17368. };
  17369. const redo$1 = (editor, index, data) => {
  17370. let level;
  17371. if (index.get() < data.length - 1) {
  17372. index.set(index.get() + 1);
  17373. level = data[index.get()];
  17374. applyToEditor(editor, level, false);
  17375. editor.setDirty(true);
  17376. editor.dispatch('Redo', { level });
  17377. }
  17378. return level;
  17379. };
  17380. const undo$1 = (editor, undoManager, locks, index) => {
  17381. let level;
  17382. if (undoManager.typing) {
  17383. undoManager.add();
  17384. undoManager.typing = false;
  17385. setTyping(undoManager, false, locks);
  17386. }
  17387. if (index.get() > 0) {
  17388. index.set(index.get() - 1);
  17389. level = undoManager.data[index.get()];
  17390. applyToEditor(editor, level, true);
  17391. editor.setDirty(true);
  17392. editor.dispatch('Undo', { level });
  17393. }
  17394. return level;
  17395. };
  17396. const reset$1 = undoManager => {
  17397. undoManager.clear();
  17398. undoManager.add();
  17399. };
  17400. const hasUndo$1 = (editor, undoManager, index) => index.get() > 0 || undoManager.typing && undoManager.data[0] && !isEq$1(createFromEditor(editor), undoManager.data[0]);
  17401. const hasRedo$1 = (undoManager, index) => index.get() < undoManager.data.length - 1 && !undoManager.typing;
  17402. const transact$1 = (undoManager, locks, callback) => {
  17403. endTyping(undoManager, locks);
  17404. undoManager.beforeChange();
  17405. undoManager.ignore(callback);
  17406. return undoManager.add();
  17407. };
  17408. const ignore$1 = (locks, callback) => {
  17409. try {
  17410. locks.set(locks.get() + 1);
  17411. callback();
  17412. } finally {
  17413. locks.set(locks.get() - 1);
  17414. }
  17415. };
  17416. const addVisualInternal = (editor, elm) => {
  17417. const dom = editor.dom;
  17418. const scope = isNonNullable(elm) ? elm : editor.getBody();
  17419. each$e(dom.select('table,a', scope), matchedElm => {
  17420. switch (matchedElm.nodeName) {
  17421. case 'TABLE':
  17422. const cls = getVisualAidsTableClass(editor);
  17423. const value = dom.getAttrib(matchedElm, 'border');
  17424. if ((!value || value === '0') && editor.hasVisual) {
  17425. dom.addClass(matchedElm, cls);
  17426. } else {
  17427. dom.removeClass(matchedElm, cls);
  17428. }
  17429. break;
  17430. case 'A':
  17431. if (!dom.getAttrib(matchedElm, 'href')) {
  17432. const value = dom.getAttrib(matchedElm, 'name') || matchedElm.id;
  17433. const cls = getVisualAidsAnchorClass(editor);
  17434. if (value && editor.hasVisual) {
  17435. dom.addClass(matchedElm, cls);
  17436. } else {
  17437. dom.removeClass(matchedElm, cls);
  17438. }
  17439. }
  17440. break;
  17441. }
  17442. });
  17443. editor.dispatch('VisualAid', {
  17444. element: elm,
  17445. hasVisual: editor.hasVisual
  17446. });
  17447. };
  17448. const makePlainAdaptor = editor => ({
  17449. init: { bindEvents: noop },
  17450. undoManager: {
  17451. beforeChange: (locks, beforeBookmark) => beforeChange$1(editor, locks, beforeBookmark),
  17452. add: (undoManager, index, locks, beforeBookmark, level, event) => addUndoLevel$1(editor, undoManager, index, locks, beforeBookmark, level, event),
  17453. undo: (undoManager, locks, index) => undo$1(editor, undoManager, locks, index),
  17454. redo: (index, data) => redo$1(editor, index, data),
  17455. clear: (undoManager, index) => clear$1(editor, undoManager, index),
  17456. reset: undoManager => reset$1(undoManager),
  17457. hasUndo: (undoManager, index) => hasUndo$1(editor, undoManager, index),
  17458. hasRedo: (undoManager, index) => hasRedo$1(undoManager, index),
  17459. transact: (undoManager, locks, callback) => transact$1(undoManager, locks, callback),
  17460. ignore: (locks, callback) => ignore$1(locks, callback),
  17461. extra: (undoManager, index, callback1, callback2) => extra$1(editor, undoManager, index, callback1, callback2)
  17462. },
  17463. formatter: {
  17464. match: (name, vars, node, similar) => match$2(editor, name, vars, node, similar),
  17465. matchAll: (names, vars) => matchAll(editor, names, vars),
  17466. matchNode: (node, name, vars, similar) => matchNode(editor, node, name, vars, similar),
  17467. canApply: name => canApply(editor, name),
  17468. closest: names => closest$1(editor, names),
  17469. apply: (name, vars, node) => applyFormat$1(editor, name, vars, node),
  17470. remove: (name, vars, node, similar) => remove$2(editor, name, vars, node, similar),
  17471. toggle: (name, vars, node) => toggle(editor, name, vars, node),
  17472. formatChanged: (registeredFormatListeners, formats, callback, similar, vars) => formatChangedInternal(editor, registeredFormatListeners, formats, callback, similar, vars)
  17473. },
  17474. editor: {
  17475. getContent: args => getContentInternal(editor, args),
  17476. setContent: (content, args) => setContentInternal(editor, content, args),
  17477. insertContent: (value, details) => insertHtmlAtCaret(editor, value, details),
  17478. addVisual: elm => addVisualInternal(editor, elm)
  17479. },
  17480. selection: { getContent: (format, args) => getSelectedContentInternal(editor, format, args) },
  17481. autocompleter: {
  17482. addDecoration: range => create$9(editor, range),
  17483. removeDecoration: () => remove$3(editor, SugarElement.fromDom(editor.getBody()))
  17484. },
  17485. raw: { getModel: () => Optional.none() }
  17486. });
  17487. const makeRtcAdaptor = rtcEditor => {
  17488. const defaultVars = vars => isObject(vars) ? vars : {};
  17489. const {init, undoManager, formatter, editor, selection, autocompleter, raw} = rtcEditor;
  17490. return {
  17491. init: { bindEvents: init.bindEvents },
  17492. undoManager: {
  17493. beforeChange: undoManager.beforeChange,
  17494. add: undoManager.add,
  17495. undo: undoManager.undo,
  17496. redo: undoManager.redo,
  17497. clear: undoManager.clear,
  17498. reset: undoManager.reset,
  17499. hasUndo: undoManager.hasUndo,
  17500. hasRedo: undoManager.hasRedo,
  17501. transact: (_undoManager, _locks, fn) => undoManager.transact(fn),
  17502. ignore: (_locks, callback) => undoManager.ignore(callback),
  17503. extra: (_undoManager, _index, callback1, callback2) => undoManager.extra(callback1, callback2)
  17504. },
  17505. formatter: {
  17506. match: (name, vars, _node, similar) => formatter.match(name, defaultVars(vars), similar),
  17507. matchAll: formatter.matchAll,
  17508. matchNode: formatter.matchNode,
  17509. canApply: name => formatter.canApply(name),
  17510. closest: names => formatter.closest(names),
  17511. apply: (name, vars, _node) => formatter.apply(name, defaultVars(vars)),
  17512. remove: (name, vars, _node, _similar) => formatter.remove(name, defaultVars(vars)),
  17513. toggle: (name, vars, _node) => formatter.toggle(name, defaultVars(vars)),
  17514. formatChanged: (_rfl, formats, callback, similar, vars) => formatter.formatChanged(formats, callback, similar, vars)
  17515. },
  17516. editor: {
  17517. getContent: args => editor.getContent(args),
  17518. setContent: (content, args) => {
  17519. return {
  17520. content: editor.setContent(content, args),
  17521. html: ''
  17522. };
  17523. },
  17524. insertContent: (content, _details) => {
  17525. editor.insertContent(content);
  17526. return '';
  17527. },
  17528. addVisual: editor.addVisual
  17529. },
  17530. selection: { getContent: (_format, args) => selection.getContent(args) },
  17531. autocompleter: {
  17532. addDecoration: autocompleter.addDecoration,
  17533. removeDecoration: autocompleter.removeDecoration
  17534. },
  17535. raw: { getModel: () => Optional.some(raw.getRawModel()) }
  17536. };
  17537. };
  17538. const makeNoopAdaptor = () => {
  17539. const nul = constant(null);
  17540. const empty = constant('');
  17541. return {
  17542. init: { bindEvents: noop },
  17543. undoManager: {
  17544. beforeChange: noop,
  17545. add: nul,
  17546. undo: nul,
  17547. redo: nul,
  17548. clear: noop,
  17549. reset: noop,
  17550. hasUndo: never,
  17551. hasRedo: never,
  17552. transact: nul,
  17553. ignore: noop,
  17554. extra: noop
  17555. },
  17556. formatter: {
  17557. match: never,
  17558. matchAll: constant([]),
  17559. matchNode: constant(undefined),
  17560. canApply: never,
  17561. closest: empty,
  17562. apply: noop,
  17563. remove: noop,
  17564. toggle: noop,
  17565. formatChanged: constant({ unbind: noop })
  17566. },
  17567. editor: {
  17568. getContent: empty,
  17569. setContent: constant({
  17570. content: '',
  17571. html: ''
  17572. }),
  17573. insertContent: constant(''),
  17574. addVisual: noop
  17575. },
  17576. selection: { getContent: empty },
  17577. autocompleter: {
  17578. addDecoration: noop,
  17579. removeDecoration: noop
  17580. },
  17581. raw: { getModel: constant(Optional.none()) }
  17582. };
  17583. };
  17584. const isRtc = editor => has$2(editor.plugins, 'rtc');
  17585. const getRtcSetup = editor => get$a(editor.plugins, 'rtc').bind(rtcPlugin => Optional.from(rtcPlugin.setup));
  17586. const setup$s = editor => {
  17587. const editorCast = editor;
  17588. return getRtcSetup(editor).fold(() => {
  17589. editorCast.rtcInstance = makePlainAdaptor(editor);
  17590. return Optional.none();
  17591. }, setup => {
  17592. editorCast.rtcInstance = makeNoopAdaptor();
  17593. return Optional.some(() => setup().then(rtcEditor => {
  17594. editorCast.rtcInstance = makeRtcAdaptor(rtcEditor);
  17595. return rtcEditor.rtc.isRemote;
  17596. }));
  17597. });
  17598. };
  17599. const getRtcInstanceWithFallback = editor => editor.rtcInstance ? editor.rtcInstance : makePlainAdaptor(editor);
  17600. const getRtcInstanceWithError = editor => {
  17601. const rtcInstance = editor.rtcInstance;
  17602. if (!rtcInstance) {
  17603. throw new Error('Failed to get RTC instance not yet initialized.');
  17604. } else {
  17605. return rtcInstance;
  17606. }
  17607. };
  17608. const beforeChange = (editor, locks, beforeBookmark) => {
  17609. getRtcInstanceWithError(editor).undoManager.beforeChange(locks, beforeBookmark);
  17610. };
  17611. const addUndoLevel = (editor, undoManager, index, locks, beforeBookmark, level, event) => getRtcInstanceWithError(editor).undoManager.add(undoManager, index, locks, beforeBookmark, level, event);
  17612. const undo = (editor, undoManager, locks, index) => getRtcInstanceWithError(editor).undoManager.undo(undoManager, locks, index);
  17613. const redo = (editor, index, data) => getRtcInstanceWithError(editor).undoManager.redo(index, data);
  17614. const clear = (editor, undoManager, index) => {
  17615. getRtcInstanceWithError(editor).undoManager.clear(undoManager, index);
  17616. };
  17617. const reset = (editor, undoManager) => {
  17618. getRtcInstanceWithError(editor).undoManager.reset(undoManager);
  17619. };
  17620. const hasUndo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasUndo(undoManager, index);
  17621. const hasRedo = (editor, undoManager, index) => getRtcInstanceWithError(editor).undoManager.hasRedo(undoManager, index);
  17622. const transact = (editor, undoManager, locks, callback) => getRtcInstanceWithError(editor).undoManager.transact(undoManager, locks, callback);
  17623. const ignore = (editor, locks, callback) => {
  17624. getRtcInstanceWithError(editor).undoManager.ignore(locks, callback);
  17625. };
  17626. const extra = (editor, undoManager, index, callback1, callback2) => {
  17627. getRtcInstanceWithError(editor).undoManager.extra(undoManager, index, callback1, callback2);
  17628. };
  17629. const matchFormat = (editor, name, vars, node, similar) => getRtcInstanceWithError(editor).formatter.match(name, vars, node, similar);
  17630. const matchAllFormats = (editor, names, vars) => getRtcInstanceWithError(editor).formatter.matchAll(names, vars);
  17631. const matchNodeFormat = (editor, node, name, vars, similar) => getRtcInstanceWithError(editor).formatter.matchNode(node, name, vars, similar);
  17632. const canApplyFormat = (editor, name) => getRtcInstanceWithError(editor).formatter.canApply(name);
  17633. const closestFormat = (editor, names) => getRtcInstanceWithError(editor).formatter.closest(names);
  17634. const applyFormat = (editor, name, vars, node) => {
  17635. getRtcInstanceWithError(editor).formatter.apply(name, vars, node);
  17636. };
  17637. const removeFormat = (editor, name, vars, node, similar) => {
  17638. getRtcInstanceWithError(editor).formatter.remove(name, vars, node, similar);
  17639. };
  17640. const toggleFormat = (editor, name, vars, node) => {
  17641. getRtcInstanceWithError(editor).formatter.toggle(name, vars, node);
  17642. };
  17643. const formatChanged = (editor, registeredFormatListeners, formats, callback, similar, vars) => getRtcInstanceWithError(editor).formatter.formatChanged(registeredFormatListeners, formats, callback, similar, vars);
  17644. const getContent$2 = (editor, args) => getRtcInstanceWithFallback(editor).editor.getContent(args);
  17645. const setContent$2 = (editor, content, args) => getRtcInstanceWithFallback(editor).editor.setContent(content, args);
  17646. const insertContent$1 = (editor, value, details) => getRtcInstanceWithFallback(editor).editor.insertContent(value, details);
  17647. const getSelectedContent = (editor, format, args) => getRtcInstanceWithError(editor).selection.getContent(format, args);
  17648. const addVisual$1 = (editor, elm) => getRtcInstanceWithError(editor).editor.addVisual(elm);
  17649. const bindEvents = editor => getRtcInstanceWithError(editor).init.bindEvents();
  17650. const addAutocompleterDecoration = (editor, range) => getRtcInstanceWithError(editor).autocompleter.addDecoration(range);
  17651. const removeAutocompleterDecoration = editor => getRtcInstanceWithError(editor).autocompleter.removeDecoration();
  17652. const getContent$1 = (editor, args = {}) => {
  17653. const format = args.format ? args.format : 'html';
  17654. return getSelectedContent(editor, format, args);
  17655. };
  17656. const removeEmpty = text => {
  17657. if (text.dom.length === 0) {
  17658. remove$6(text);
  17659. return Optional.none();
  17660. } else {
  17661. return Optional.some(text);
  17662. }
  17663. };
  17664. const walkPastBookmark = (node, start) => node.filter(elm => BookmarkManager.isBookmarkNode(elm.dom)).bind(start ? nextSibling : prevSibling);
  17665. const merge$1 = (outer, inner, rng, start) => {
  17666. const outerElm = outer.dom;
  17667. const innerElm = inner.dom;
  17668. const oldLength = start ? outerElm.length : innerElm.length;
  17669. if (start) {
  17670. mergeTextNodes(outerElm, innerElm, false, !start);
  17671. rng.setStart(innerElm, oldLength);
  17672. } else {
  17673. mergeTextNodes(innerElm, outerElm, false, !start);
  17674. rng.setEnd(innerElm, oldLength);
  17675. }
  17676. };
  17677. const normalizeTextIfRequired = (inner, start) => {
  17678. parent(inner).each(root => {
  17679. const text = inner.dom;
  17680. if (start && needsToBeNbspLeft(root, CaretPosition(text, 0))) {
  17681. normalizeWhitespaceAfter(text, 0);
  17682. } else if (!start && needsToBeNbspRight(root, CaretPosition(text, text.length))) {
  17683. normalizeWhitespaceBefore(text, text.length);
  17684. }
  17685. });
  17686. };
  17687. const mergeAndNormalizeText = (outerNode, innerNode, rng, start) => {
  17688. outerNode.bind(outer => {
  17689. const normalizer = start ? normalizeWhitespaceBefore : normalizeWhitespaceAfter;
  17690. normalizer(outer.dom, start ? outer.dom.length : 0);
  17691. return innerNode.filter(isText$b).map(inner => merge$1(outer, inner, rng, start));
  17692. }).orThunk(() => {
  17693. const innerTextNode = walkPastBookmark(innerNode, start).or(innerNode).filter(isText$b);
  17694. return innerTextNode.map(inner => normalizeTextIfRequired(inner, start));
  17695. });
  17696. };
  17697. const rngSetContent = (rng, fragment) => {
  17698. const firstChild = Optional.from(fragment.firstChild).map(SugarElement.fromDom);
  17699. const lastChild = Optional.from(fragment.lastChild).map(SugarElement.fromDom);
  17700. rng.deleteContents();
  17701. rng.insertNode(fragment);
  17702. const prevText = firstChild.bind(prevSibling).filter(isText$b).bind(removeEmpty);
  17703. const nextText = lastChild.bind(nextSibling).filter(isText$b).bind(removeEmpty);
  17704. mergeAndNormalizeText(prevText, firstChild, rng, true);
  17705. mergeAndNormalizeText(nextText, lastChild, rng, false);
  17706. rng.collapse(false);
  17707. };
  17708. const setupArgs$2 = (args, content) => ({
  17709. format: 'html',
  17710. ...args,
  17711. set: true,
  17712. selection: true,
  17713. content
  17714. });
  17715. const cleanContent = (editor, args) => {
  17716. if (args.format !== 'raw') {
  17717. const rng = editor.selection.getRng();
  17718. const contextBlock = editor.dom.getParent(rng.commonAncestorContainer, editor.dom.isBlock);
  17719. const contextArgs = contextBlock ? { context: contextBlock.nodeName.toLowerCase() } : {};
  17720. const node = editor.parser.parse(args.content, {
  17721. forced_root_block: false,
  17722. ...contextArgs,
  17723. ...args
  17724. });
  17725. return HtmlSerializer({ validate: false }, editor.schema).serialize(node);
  17726. } else {
  17727. return args.content;
  17728. }
  17729. };
  17730. const setContent$1 = (editor, content, args = {}) => {
  17731. const defaultedArgs = setupArgs$2(args, content);
  17732. preProcessSetContent(editor, defaultedArgs).each(updatedArgs => {
  17733. const cleanedContent = cleanContent(editor, updatedArgs);
  17734. const rng = editor.selection.getRng();
  17735. rngSetContent(rng, rng.createContextualFragment(cleanedContent));
  17736. editor.selection.setRng(rng);
  17737. scrollRangeIntoView(editor, rng);
  17738. postProcessSetContent(editor, cleanedContent, updatedArgs);
  17739. });
  17740. };
  17741. const deleteFromCallbackMap = (callbackMap, selector, callback) => {
  17742. if (has$2(callbackMap, selector)) {
  17743. const newCallbacks = filter$5(callbackMap[selector], cb => cb !== callback);
  17744. if (newCallbacks.length === 0) {
  17745. delete callbackMap[selector];
  17746. } else {
  17747. callbackMap[selector] = newCallbacks;
  17748. }
  17749. }
  17750. };
  17751. var SelectorChanged = (dom, editor) => {
  17752. let selectorChangedData;
  17753. let currentSelectors;
  17754. const findMatchingNode = (selector, nodes) => find$2(nodes, node => dom.is(node, selector));
  17755. const getParents = elem => dom.getParents(elem, undefined, dom.getRoot());
  17756. const setup = () => {
  17757. selectorChangedData = {};
  17758. currentSelectors = {};
  17759. editor.on('NodeChange', e => {
  17760. const node = e.element;
  17761. const parents = getParents(node);
  17762. const matchedSelectors = {};
  17763. each$d(selectorChangedData, (callbacks, selector) => {
  17764. findMatchingNode(selector, parents).each(node => {
  17765. if (!currentSelectors[selector]) {
  17766. each$e(callbacks, callback => {
  17767. callback(true, {
  17768. node,
  17769. selector,
  17770. parents
  17771. });
  17772. });
  17773. currentSelectors[selector] = callbacks;
  17774. }
  17775. matchedSelectors[selector] = callbacks;
  17776. });
  17777. });
  17778. each$d(currentSelectors, (callbacks, selector) => {
  17779. if (!matchedSelectors[selector]) {
  17780. delete currentSelectors[selector];
  17781. each$e(callbacks, callback => {
  17782. callback(false, {
  17783. node,
  17784. selector,
  17785. parents
  17786. });
  17787. });
  17788. }
  17789. });
  17790. });
  17791. };
  17792. return {
  17793. selectorChangedWithUnbind: (selector, callback) => {
  17794. if (!selectorChangedData) {
  17795. setup();
  17796. }
  17797. if (!selectorChangedData[selector]) {
  17798. selectorChangedData[selector] = [];
  17799. }
  17800. selectorChangedData[selector].push(callback);
  17801. findMatchingNode(selector, getParents(editor.selection.getStart())).each(() => {
  17802. currentSelectors[selector] = selectorChangedData[selector];
  17803. });
  17804. return {
  17805. unbind: () => {
  17806. deleteFromCallbackMap(selectorChangedData, selector, callback);
  17807. deleteFromCallbackMap(currentSelectors, selector, callback);
  17808. }
  17809. };
  17810. }
  17811. };
  17812. };
  17813. const isAttachedToDom = node => {
  17814. return !!(node && node.ownerDocument) && contains(SugarElement.fromDom(node.ownerDocument), SugarElement.fromDom(node));
  17815. };
  17816. const isValidRange = rng => {
  17817. if (!rng) {
  17818. return false;
  17819. } else {
  17820. return isAttachedToDom(rng.startContainer) && isAttachedToDom(rng.endContainer);
  17821. }
  17822. };
  17823. const EditorSelection = (dom, win, serializer, editor) => {
  17824. let selectedRange;
  17825. let explicitRange;
  17826. const {selectorChangedWithUnbind} = SelectorChanged(dom, editor);
  17827. const setCursorLocation = (node, offset) => {
  17828. const rng = dom.createRng();
  17829. if (isNonNullable(node) && isNonNullable(offset)) {
  17830. rng.setStart(node, offset);
  17831. rng.setEnd(node, offset);
  17832. setRng(rng);
  17833. collapse(false);
  17834. } else {
  17835. moveEndPoint(dom, rng, editor.getBody(), true);
  17836. setRng(rng);
  17837. }
  17838. };
  17839. const getContent = args => getContent$1(editor, args);
  17840. const setContent = (content, args) => setContent$1(editor, content, args);
  17841. const getStart$1 = real => getStart(editor.getBody(), getRng$1(), real);
  17842. const getEnd = real => getEnd$1(editor.getBody(), getRng$1(), real);
  17843. const getBookmark = (type, normalized) => bookmarkManager.getBookmark(type, normalized);
  17844. const moveToBookmark = bookmark => bookmarkManager.moveToBookmark(bookmark);
  17845. const select$1 = (node, content) => {
  17846. select(dom, node, content).each(setRng);
  17847. return node;
  17848. };
  17849. const isCollapsed = () => {
  17850. const rng = getRng$1(), sel = getSel();
  17851. if (!rng || rng.item) {
  17852. return false;
  17853. }
  17854. if (rng.compareEndPoints) {
  17855. return rng.compareEndPoints('StartToEnd', rng) === 0;
  17856. }
  17857. return !sel || rng.collapsed;
  17858. };
  17859. const collapse = toStart => {
  17860. const rng = getRng$1();
  17861. rng.collapse(!!toStart);
  17862. setRng(rng);
  17863. };
  17864. const getSel = () => win.getSelection ? win.getSelection() : win.document.selection;
  17865. const getRng$1 = () => {
  17866. let rng;
  17867. const tryCompareBoundaryPoints = (how, sourceRange, destinationRange) => {
  17868. try {
  17869. return sourceRange.compareBoundaryPoints(how, destinationRange);
  17870. } catch (ex) {
  17871. return -1;
  17872. }
  17873. };
  17874. const doc = win.document;
  17875. if (isNonNullable(editor.bookmark) && !hasFocus(editor)) {
  17876. const bookmark = getRng(editor);
  17877. if (bookmark.isSome()) {
  17878. return bookmark.map(r => processRanges(editor, [r])[0]).getOr(doc.createRange());
  17879. }
  17880. }
  17881. try {
  17882. const selection = getSel();
  17883. if (selection && !isRestrictedNode(selection.anchorNode)) {
  17884. if (selection.rangeCount > 0) {
  17885. rng = selection.getRangeAt(0);
  17886. } else {
  17887. rng = doc.createRange();
  17888. }
  17889. rng = processRanges(editor, [rng])[0];
  17890. }
  17891. } catch (ex) {
  17892. }
  17893. if (!rng) {
  17894. rng = doc.createRange();
  17895. }
  17896. if (isDocument$1(rng.startContainer) && rng.collapsed) {
  17897. const elm = dom.getRoot();
  17898. rng.setStart(elm, 0);
  17899. rng.setEnd(elm, 0);
  17900. }
  17901. if (selectedRange && explicitRange) {
  17902. if (tryCompareBoundaryPoints(rng.START_TO_START, rng, selectedRange) === 0 && tryCompareBoundaryPoints(rng.END_TO_END, rng, selectedRange) === 0) {
  17903. rng = explicitRange;
  17904. } else {
  17905. selectedRange = null;
  17906. explicitRange = null;
  17907. }
  17908. }
  17909. return rng;
  17910. };
  17911. const setRng = (rng, forward) => {
  17912. if (!isValidRange(rng)) {
  17913. return;
  17914. }
  17915. const sel = getSel();
  17916. const evt = editor.dispatch('SetSelectionRange', {
  17917. range: rng,
  17918. forward
  17919. });
  17920. rng = evt.range;
  17921. if (sel) {
  17922. explicitRange = rng;
  17923. try {
  17924. sel.removeAllRanges();
  17925. sel.addRange(rng);
  17926. } catch (ex) {
  17927. }
  17928. if (forward === false && sel.extend) {
  17929. sel.collapse(rng.endContainer, rng.endOffset);
  17930. sel.extend(rng.startContainer, rng.startOffset);
  17931. }
  17932. selectedRange = sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
  17933. }
  17934. if (!rng.collapsed && rng.startContainer === rng.endContainer && (sel === null || sel === void 0 ? void 0 : sel.setBaseAndExtent)) {
  17935. if (rng.endOffset - rng.startOffset < 2) {
  17936. if (rng.startContainer.hasChildNodes()) {
  17937. const node = rng.startContainer.childNodes[rng.startOffset];
  17938. if (node && node.nodeName === 'IMG') {
  17939. sel.setBaseAndExtent(rng.startContainer, rng.startOffset, rng.endContainer, rng.endOffset);
  17940. if (sel.anchorNode !== rng.startContainer || sel.focusNode !== rng.endContainer) {
  17941. sel.setBaseAndExtent(node, 0, node, 1);
  17942. }
  17943. }
  17944. }
  17945. }
  17946. }
  17947. editor.dispatch('AfterSetSelectionRange', {
  17948. range: rng,
  17949. forward
  17950. });
  17951. };
  17952. const setNode = elm => {
  17953. setContent(dom.getOuterHTML(elm));
  17954. return elm;
  17955. };
  17956. const getNode$1 = () => getNode(editor.getBody(), getRng$1());
  17957. const getSelectedBlocks$1 = (startElm, endElm) => getSelectedBlocks(dom, getRng$1(), startElm, endElm);
  17958. const isForward = () => {
  17959. const sel = getSel();
  17960. const anchorNode = sel === null || sel === void 0 ? void 0 : sel.anchorNode;
  17961. const focusNode = sel === null || sel === void 0 ? void 0 : sel.focusNode;
  17962. if (!sel || !anchorNode || !focusNode || isRestrictedNode(anchorNode) || isRestrictedNode(focusNode)) {
  17963. return true;
  17964. }
  17965. const anchorRange = dom.createRng();
  17966. const focusRange = dom.createRng();
  17967. try {
  17968. anchorRange.setStart(anchorNode, sel.anchorOffset);
  17969. anchorRange.collapse(true);
  17970. focusRange.setStart(focusNode, sel.focusOffset);
  17971. focusRange.collapse(true);
  17972. } catch (e) {
  17973. return true;
  17974. }
  17975. return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
  17976. };
  17977. const normalize = () => {
  17978. const rng = getRng$1();
  17979. const sel = getSel();
  17980. if (!hasMultipleRanges(sel) && hasAnyRanges(editor)) {
  17981. const normRng = normalize$2(dom, rng);
  17982. normRng.each(normRng => {
  17983. setRng(normRng, isForward());
  17984. });
  17985. return normRng.getOr(rng);
  17986. }
  17987. return rng;
  17988. };
  17989. const selectorChanged = (selector, callback) => {
  17990. selectorChangedWithUnbind(selector, callback);
  17991. return exports;
  17992. };
  17993. const getScrollContainer = () => {
  17994. let scrollContainer;
  17995. let node = dom.getRoot();
  17996. while (node && node.nodeName !== 'BODY') {
  17997. if (node.scrollHeight > node.clientHeight) {
  17998. scrollContainer = node;
  17999. break;
  18000. }
  18001. node = node.parentNode;
  18002. }
  18003. return scrollContainer;
  18004. };
  18005. const scrollIntoView = (elm, alignToTop) => {
  18006. if (isNonNullable(elm)) {
  18007. scrollElementIntoView(editor, elm, alignToTop);
  18008. } else {
  18009. scrollRangeIntoView(editor, getRng$1(), alignToTop);
  18010. }
  18011. };
  18012. const placeCaretAt = (clientX, clientY) => setRng(fromPoint(clientX, clientY, editor.getDoc()));
  18013. const getBoundingClientRect = () => {
  18014. const rng = getRng$1();
  18015. return rng.collapsed ? CaretPosition.fromRangeStart(rng).getClientRects()[0] : rng.getBoundingClientRect();
  18016. };
  18017. const destroy = () => {
  18018. win = selectedRange = explicitRange = null;
  18019. controlSelection.destroy();
  18020. };
  18021. const expand = (options = { type: 'word' }) => setRng(RangeUtils(dom).expand(getRng$1(), options));
  18022. const exports = {
  18023. dom,
  18024. win,
  18025. serializer,
  18026. editor,
  18027. expand,
  18028. collapse,
  18029. setCursorLocation,
  18030. getContent,
  18031. setContent,
  18032. getBookmark,
  18033. moveToBookmark,
  18034. select: select$1,
  18035. isCollapsed,
  18036. isForward,
  18037. setNode,
  18038. getNode: getNode$1,
  18039. getSel,
  18040. setRng,
  18041. getRng: getRng$1,
  18042. getStart: getStart$1,
  18043. getEnd,
  18044. getSelectedBlocks: getSelectedBlocks$1,
  18045. normalize,
  18046. selectorChanged,
  18047. selectorChangedWithUnbind,
  18048. getScrollContainer,
  18049. scrollIntoView,
  18050. placeCaretAt,
  18051. getBoundingClientRect,
  18052. destroy
  18053. };
  18054. const bookmarkManager = BookmarkManager(exports);
  18055. const controlSelection = ControlSelection(exports, editor);
  18056. exports.bookmarkManager = bookmarkManager;
  18057. exports.controlSelection = controlSelection;
  18058. return exports;
  18059. };
  18060. const register$3 = (htmlParser, settings, dom) => {
  18061. htmlParser.addAttributeFilter('data-mce-tabindex', (nodes, name) => {
  18062. let i = nodes.length;
  18063. while (i--) {
  18064. const node = nodes[i];
  18065. node.attr('tabindex', node.attr('data-mce-tabindex'));
  18066. node.attr(name, null);
  18067. }
  18068. });
  18069. htmlParser.addAttributeFilter('src,href,style', (nodes, name) => {
  18070. const internalName = 'data-mce-' + name;
  18071. const urlConverter = settings.url_converter;
  18072. const urlConverterScope = settings.url_converter_scope;
  18073. let i = nodes.length;
  18074. while (i--) {
  18075. const node = nodes[i];
  18076. let value = node.attr(internalName);
  18077. if (value !== undefined) {
  18078. node.attr(name, value.length > 0 ? value : null);
  18079. node.attr(internalName, null);
  18080. } else {
  18081. value = node.attr(name);
  18082. if (name === 'style') {
  18083. value = dom.serializeStyle(dom.parseStyle(value), node.name);
  18084. } else if (urlConverter) {
  18085. value = urlConverter.call(urlConverterScope, value, name, node.name);
  18086. }
  18087. node.attr(name, value.length > 0 ? value : null);
  18088. }
  18089. }
  18090. });
  18091. htmlParser.addAttributeFilter('class', nodes => {
  18092. let i = nodes.length;
  18093. while (i--) {
  18094. const node = nodes[i];
  18095. let value = node.attr('class');
  18096. if (value) {
  18097. value = value.replace(/(?:^|\s)mce-item-\w+(?!\S)/g, '');
  18098. node.attr('class', value.length > 0 ? value : null);
  18099. }
  18100. }
  18101. });
  18102. htmlParser.addAttributeFilter('data-mce-type', (nodes, name, args) => {
  18103. let i = nodes.length;
  18104. while (i--) {
  18105. const node = nodes[i];
  18106. if (node.attr('data-mce-type') === 'bookmark' && !args.cleanup) {
  18107. const hasChildren = Optional.from(node.firstChild).exists(firstChild => {
  18108. var _a;
  18109. return !isZwsp((_a = firstChild.value) !== null && _a !== void 0 ? _a : '');
  18110. });
  18111. if (hasChildren) {
  18112. node.unwrap();
  18113. } else {
  18114. node.remove();
  18115. }
  18116. }
  18117. }
  18118. });
  18119. htmlParser.addNodeFilter('noscript', nodes => {
  18120. var _a;
  18121. let i = nodes.length;
  18122. while (i--) {
  18123. const node = nodes[i].firstChild;
  18124. if (node) {
  18125. node.value = Entities.decode((_a = node.value) !== null && _a !== void 0 ? _a : '');
  18126. }
  18127. }
  18128. });
  18129. htmlParser.addNodeFilter('script,style', (nodes, name) => {
  18130. var _a;
  18131. const trim = value => {
  18132. return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n').replace(/^[\r\n]*|[\r\n]*$/g, '').replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '').replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
  18133. };
  18134. let i = nodes.length;
  18135. while (i--) {
  18136. const node = nodes[i];
  18137. const firstChild = node.firstChild;
  18138. const value = (_a = firstChild === null || firstChild === void 0 ? void 0 : firstChild.value) !== null && _a !== void 0 ? _a : '';
  18139. if (name === 'script') {
  18140. const type = node.attr('type');
  18141. if (type) {
  18142. node.attr('type', type === 'mce-no/type' ? null : type.replace(/^mce\-/, ''));
  18143. }
  18144. if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
  18145. firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
  18146. }
  18147. } else {
  18148. if (settings.element_format === 'xhtml' && firstChild && value.length > 0) {
  18149. firstChild.value = '<!--\n' + trim(value) + '\n-->';
  18150. }
  18151. }
  18152. }
  18153. });
  18154. htmlParser.addNodeFilter('#comment', nodes => {
  18155. let i = nodes.length;
  18156. while (i--) {
  18157. const node = nodes[i];
  18158. const value = node.value;
  18159. if (settings.preserve_cdata && (value === null || value === void 0 ? void 0 : value.indexOf('[CDATA[')) === 0) {
  18160. node.name = '#cdata';
  18161. node.type = 4;
  18162. node.value = dom.decode(value.replace(/^\[CDATA\[|\]\]$/g, ''));
  18163. } else if ((value === null || value === void 0 ? void 0 : value.indexOf('mce:protected ')) === 0) {
  18164. node.name = '#text';
  18165. node.type = 3;
  18166. node.raw = true;
  18167. node.value = unescape(value).substr(14);
  18168. }
  18169. }
  18170. });
  18171. htmlParser.addNodeFilter('xml:namespace,input', (nodes, name) => {
  18172. let i = nodes.length;
  18173. while (i--) {
  18174. const node = nodes[i];
  18175. if (node.type === 7) {
  18176. node.remove();
  18177. } else if (node.type === 1) {
  18178. if (name === 'input' && !node.attr('type')) {
  18179. node.attr('type', 'text');
  18180. }
  18181. }
  18182. }
  18183. });
  18184. htmlParser.addAttributeFilter('data-mce-type', nodes => {
  18185. each$e(nodes, node => {
  18186. if (node.attr('data-mce-type') === 'format-caret') {
  18187. if (node.isEmpty(htmlParser.schema.getNonEmptyElements())) {
  18188. node.remove();
  18189. } else {
  18190. node.unwrap();
  18191. }
  18192. }
  18193. });
  18194. });
  18195. htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style,' + 'data-mce-selected,data-mce-expando,data-mce-block,' + 'data-mce-type,data-mce-resize,data-mce-placeholder', (nodes, name) => {
  18196. let i = nodes.length;
  18197. while (i--) {
  18198. nodes[i].attr(name, null);
  18199. }
  18200. });
  18201. };
  18202. const trimTrailingBr = rootNode => {
  18203. const isBr = node => {
  18204. return (node === null || node === void 0 ? void 0 : node.name) === 'br';
  18205. };
  18206. const brNode1 = rootNode.lastChild;
  18207. if (isBr(brNode1)) {
  18208. const brNode2 = brNode1.prev;
  18209. if (isBr(brNode2)) {
  18210. brNode1.remove();
  18211. brNode2.remove();
  18212. }
  18213. }
  18214. };
  18215. const preProcess$1 = (editor, node, args) => {
  18216. let oldDoc;
  18217. const dom = editor.dom;
  18218. let clonedNode = node.cloneNode(true);
  18219. const impl = document.implementation;
  18220. if (impl.createHTMLDocument) {
  18221. const doc = impl.createHTMLDocument('');
  18222. Tools.each(clonedNode.nodeName === 'BODY' ? clonedNode.childNodes : [clonedNode], node => {
  18223. doc.body.appendChild(doc.importNode(node, true));
  18224. });
  18225. if (clonedNode.nodeName !== 'BODY') {
  18226. clonedNode = doc.body.firstChild;
  18227. } else {
  18228. clonedNode = doc.body;
  18229. }
  18230. oldDoc = dom.doc;
  18231. dom.doc = doc;
  18232. }
  18233. firePreProcess(editor, {
  18234. ...args,
  18235. node: clonedNode
  18236. });
  18237. if (oldDoc) {
  18238. dom.doc = oldDoc;
  18239. }
  18240. return clonedNode;
  18241. };
  18242. const shouldFireEvent = (editor, args) => {
  18243. return isNonNullable(editor) && editor.hasEventListeners('PreProcess') && !args.no_events;
  18244. };
  18245. const process$1 = (editor, node, args) => {
  18246. return shouldFireEvent(editor, args) ? preProcess$1(editor, node, args) : node;
  18247. };
  18248. const addTempAttr = (htmlParser, tempAttrs, name) => {
  18249. if (Tools.inArray(tempAttrs, name) === -1) {
  18250. htmlParser.addAttributeFilter(name, (nodes, name) => {
  18251. let i = nodes.length;
  18252. while (i--) {
  18253. nodes[i].attr(name, null);
  18254. }
  18255. });
  18256. tempAttrs.push(name);
  18257. }
  18258. };
  18259. const postProcess = (editor, args, content) => {
  18260. if (!args.no_events && editor) {
  18261. const outArgs = firePostProcess(editor, {
  18262. ...args,
  18263. content
  18264. });
  18265. return outArgs.content;
  18266. } else {
  18267. return content;
  18268. }
  18269. };
  18270. const getHtmlFromNode = (dom, node, args) => {
  18271. const html = trim$1(args.getInner ? node.innerHTML : dom.getOuterHTML(node));
  18272. return args.selection || isWsPreserveElement(SugarElement.fromDom(node)) ? html : Tools.trim(html);
  18273. };
  18274. const parseHtml = (htmlParser, html, args) => {
  18275. const parserArgs = args.selection ? {
  18276. forced_root_block: false,
  18277. ...args
  18278. } : args;
  18279. const rootNode = htmlParser.parse(html, parserArgs);
  18280. trimTrailingBr(rootNode);
  18281. return rootNode;
  18282. };
  18283. const serializeNode = (settings, schema, node) => {
  18284. const htmlSerializer = HtmlSerializer(settings, schema);
  18285. return htmlSerializer.serialize(node);
  18286. };
  18287. const toHtml = (editor, settings, schema, rootNode, args) => {
  18288. const content = serializeNode(settings, schema, rootNode);
  18289. return postProcess(editor, args, content);
  18290. };
  18291. const DomSerializerImpl = (settings, editor) => {
  18292. const tempAttrs = ['data-mce-selected'];
  18293. const dom = editor && editor.dom ? editor.dom : DOMUtils.DOM;
  18294. const schema = editor && editor.schema ? editor.schema : Schema(settings);
  18295. settings.entity_encoding = settings.entity_encoding || 'named';
  18296. settings.remove_trailing_brs = 'remove_trailing_brs' in settings ? settings.remove_trailing_brs : true;
  18297. const htmlParser = DomParser(settings, schema);
  18298. register$3(htmlParser, settings, dom);
  18299. const serialize = (node, parserArgs = {}) => {
  18300. const args = {
  18301. format: 'html',
  18302. ...parserArgs
  18303. };
  18304. const targetNode = process$1(editor, node, args);
  18305. const html = getHtmlFromNode(dom, targetNode, args);
  18306. const rootNode = parseHtml(htmlParser, html, args);
  18307. return args.format === 'tree' ? rootNode : toHtml(editor, settings, schema, rootNode, args);
  18308. };
  18309. return {
  18310. schema,
  18311. addNodeFilter: htmlParser.addNodeFilter,
  18312. addAttributeFilter: htmlParser.addAttributeFilter,
  18313. serialize: serialize,
  18314. addRules: schema.addValidElements,
  18315. setRules: schema.setValidElements,
  18316. addTempAttr: curry(addTempAttr, htmlParser, tempAttrs),
  18317. getTempAttrs: constant(tempAttrs),
  18318. getNodeFilters: htmlParser.getNodeFilters,
  18319. getAttributeFilters: htmlParser.getAttributeFilters,
  18320. removeNodeFilter: htmlParser.removeNodeFilter,
  18321. removeAttributeFilter: htmlParser.removeAttributeFilter
  18322. };
  18323. };
  18324. const DomSerializer = (settings, editor) => {
  18325. const domSerializer = DomSerializerImpl(settings, editor);
  18326. return {
  18327. schema: domSerializer.schema,
  18328. addNodeFilter: domSerializer.addNodeFilter,
  18329. addAttributeFilter: domSerializer.addAttributeFilter,
  18330. serialize: domSerializer.serialize,
  18331. addRules: domSerializer.addRules,
  18332. setRules: domSerializer.setRules,
  18333. addTempAttr: domSerializer.addTempAttr,
  18334. getTempAttrs: domSerializer.getTempAttrs,
  18335. getNodeFilters: domSerializer.getNodeFilters,
  18336. getAttributeFilters: domSerializer.getAttributeFilters,
  18337. removeNodeFilter: domSerializer.removeNodeFilter,
  18338. removeAttributeFilter: domSerializer.removeAttributeFilter
  18339. };
  18340. };
  18341. const defaultFormat$1 = 'html';
  18342. const setupArgs$1 = (args, format) => ({
  18343. ...args,
  18344. format,
  18345. get: true,
  18346. getInner: true
  18347. });
  18348. const getContent = (editor, args = {}) => {
  18349. const format = args.format ? args.format : defaultFormat$1;
  18350. const defaultedArgs = setupArgs$1(args, format);
  18351. return preProcessGetContent(editor, defaultedArgs).fold(identity, updatedArgs => {
  18352. const content = getContent$2(editor, updatedArgs);
  18353. return postProcessGetContent(editor, content, updatedArgs);
  18354. });
  18355. };
  18356. const defaultFormat = 'html';
  18357. const setupArgs = (args, content) => ({
  18358. format: defaultFormat,
  18359. ...args,
  18360. set: true,
  18361. content
  18362. });
  18363. const setContent = (editor, content, args = {}) => {
  18364. const defaultedArgs = setupArgs(args, content);
  18365. return preProcessSetContent(editor, defaultedArgs).map(updatedArgs => {
  18366. const result = setContent$2(editor, updatedArgs.content, updatedArgs);
  18367. postProcessSetContent(editor, result.html, updatedArgs);
  18368. return result.content;
  18369. }).getOr(content);
  18370. };
  18371. const removedOptions = ('autoresize_on_init,content_editable_state,padd_empty_with_br,block_elements,' + 'boolean_attributes,editor_deselector,editor_selector,elements,file_browser_callback_types,filepicker_validator_handler,' + 'force_hex_style_colors,force_p_newlines,gecko_spellcheck,images_dataimg_filter,media_scripts,mode,move_caret_before_on_enter_elements,' + 'non_empty_elements,self_closing_elements,short_ended_elements,special,spellchecker_select_languages,spellchecker_whitelist,' + 'tab_focus,tabfocus_elements,table_responsive_width,text_block_elements,text_inline_elements,toolbar_drawer,types,validate,whitespace_elements,' + 'paste_enable_default_filters,paste_filter_drop,paste_word_valid_elements,paste_retain_style_properties,paste_convert_word_fake_lists').split(',');
  18372. const removedPlugins = 'bbcode,colorpicker,contextmenu,fullpage,legacyoutput,spellchecker,textcolor'.split(',');
  18373. const getRemovedOptions = options => {
  18374. const settingNames = filter$5(removedOptions, setting => has$2(options, setting));
  18375. const forcedRootBlock = options.forced_root_block;
  18376. if (forcedRootBlock === false || forcedRootBlock === '') {
  18377. settingNames.push('forced_root_block (false only)');
  18378. }
  18379. return sort(settingNames);
  18380. };
  18381. const getRemovedPlugins = options => {
  18382. const plugins = Tools.makeMap(options.plugins, ' ');
  18383. const hasPlugin = plugin => has$2(plugins, plugin);
  18384. const pluginNames = filter$5(removedPlugins, hasPlugin);
  18385. return sort(pluginNames);
  18386. };
  18387. const logRemovedWarnings = (rawOptions, normalizedOptions) => {
  18388. const removedOptions = getRemovedOptions(rawOptions);
  18389. const removedPlugins = getRemovedPlugins(normalizedOptions);
  18390. const hasRemovedPlugins = removedPlugins.length > 0;
  18391. const hasRemovedOptions = removedOptions.length > 0;
  18392. const isLegacyMobileTheme = normalizedOptions.theme === 'mobile';
  18393. if (hasRemovedPlugins || hasRemovedOptions || isLegacyMobileTheme) {
  18394. const listJoiner = '\n- ';
  18395. const themesMessage = isLegacyMobileTheme ? `\n\nThemes:${ listJoiner }mobile` : '';
  18396. const pluginsMessage = hasRemovedPlugins ? `\n\nPlugins:${ listJoiner }${ removedPlugins.join(listJoiner) }` : '';
  18397. const optionsMessage = hasRemovedOptions ? `\n\nOptions:${ listJoiner }${ removedOptions.join(listJoiner) }` : '';
  18398. console.warn('The following deprecated features are currently enabled and have been removed in TinyMCE 6.0. These features will no longer work and should be removed from the TinyMCE configuration. ' + 'See https://www.tiny.cloud/docs/tinymce/6/migration-from-5x/ for more information.' + themesMessage + pluginsMessage + optionsMessage);
  18399. }
  18400. };
  18401. const logWarnings = (rawOptions, normalizedOptions) => {
  18402. logRemovedWarnings(rawOptions, normalizedOptions);
  18403. };
  18404. const DOM$8 = DOMUtils.DOM;
  18405. const restoreOriginalStyles = editor => {
  18406. DOM$8.setStyle(editor.id, 'display', editor.orgDisplay);
  18407. };
  18408. const safeDestroy = x => Optional.from(x).each(x => x.destroy());
  18409. const clearDomReferences = editor => {
  18410. const ed = editor;
  18411. ed.contentAreaContainer = ed.formElement = ed.container = ed.editorContainer = null;
  18412. ed.bodyElement = ed.contentDocument = ed.contentWindow = null;
  18413. ed.iframeElement = ed.targetElm = null;
  18414. const selection = editor.selection;
  18415. if (selection) {
  18416. const dom = selection.dom;
  18417. ed.selection = selection.win = selection.dom = dom.doc = null;
  18418. }
  18419. };
  18420. const restoreForm = editor => {
  18421. const form = editor.formElement;
  18422. if (form) {
  18423. if (form._mceOldSubmit) {
  18424. form.submit = form._mceOldSubmit;
  18425. delete form._mceOldSubmit;
  18426. }
  18427. DOM$8.unbind(form, 'submit reset', editor.formEventDelegate);
  18428. }
  18429. };
  18430. const remove$1 = editor => {
  18431. if (!editor.removed) {
  18432. const {_selectionOverrides, editorUpload} = editor;
  18433. const body = editor.getBody();
  18434. const element = editor.getElement();
  18435. if (body) {
  18436. editor.save({ is_removing: true });
  18437. }
  18438. editor.removed = true;
  18439. editor.unbindAllNativeEvents();
  18440. if (editor.hasHiddenInput && isNonNullable(element === null || element === void 0 ? void 0 : element.nextSibling)) {
  18441. DOM$8.remove(element.nextSibling);
  18442. }
  18443. fireRemove(editor);
  18444. editor.editorManager.remove(editor);
  18445. if (!editor.inline && body) {
  18446. restoreOriginalStyles(editor);
  18447. }
  18448. fireDetach(editor);
  18449. DOM$8.remove(editor.getContainer());
  18450. safeDestroy(_selectionOverrides);
  18451. safeDestroy(editorUpload);
  18452. editor.destroy();
  18453. }
  18454. };
  18455. const destroy = (editor, automatic) => {
  18456. const {selection, dom} = editor;
  18457. if (editor.destroyed) {
  18458. return;
  18459. }
  18460. if (!automatic && !editor.removed) {
  18461. editor.remove();
  18462. return;
  18463. }
  18464. if (!automatic) {
  18465. editor.editorManager.off('beforeunload', editor._beforeUnload);
  18466. if (editor.theme && editor.theme.destroy) {
  18467. editor.theme.destroy();
  18468. }
  18469. safeDestroy(selection);
  18470. safeDestroy(dom);
  18471. }
  18472. restoreForm(editor);
  18473. clearDomReferences(editor);
  18474. editor.destroyed = true;
  18475. };
  18476. const CreateIconManager = () => {
  18477. const lookup = {};
  18478. const add = (id, iconPack) => {
  18479. lookup[id] = iconPack;
  18480. };
  18481. const get = id => {
  18482. if (lookup[id]) {
  18483. return lookup[id];
  18484. } else {
  18485. return { icons: {} };
  18486. }
  18487. };
  18488. const has = id => has$2(lookup, id);
  18489. return {
  18490. add,
  18491. get,
  18492. has
  18493. };
  18494. };
  18495. const IconManager = CreateIconManager();
  18496. const ModelManager = AddOnManager.ModelManager;
  18497. const getProp = (propName, elm) => {
  18498. const rawElm = elm.dom;
  18499. return rawElm[propName];
  18500. };
  18501. const getComputedSizeProp = (propName, elm) => parseInt(get$7(elm, propName), 10);
  18502. const getClientWidth = curry(getProp, 'clientWidth');
  18503. const getClientHeight = curry(getProp, 'clientHeight');
  18504. const getMarginTop = curry(getComputedSizeProp, 'margin-top');
  18505. const getMarginLeft = curry(getComputedSizeProp, 'margin-left');
  18506. const getBoundingClientRect = elm => elm.dom.getBoundingClientRect();
  18507. const isInsideElementContentArea = (bodyElm, clientX, clientY) => {
  18508. const clientWidth = getClientWidth(bodyElm);
  18509. const clientHeight = getClientHeight(bodyElm);
  18510. return clientX >= 0 && clientY >= 0 && clientX <= clientWidth && clientY <= clientHeight;
  18511. };
  18512. const transpose = (inline, elm, clientX, clientY) => {
  18513. const clientRect = getBoundingClientRect(elm);
  18514. const deltaX = inline ? clientRect.left + elm.dom.clientLeft + getMarginLeft(elm) : 0;
  18515. const deltaY = inline ? clientRect.top + elm.dom.clientTop + getMarginTop(elm) : 0;
  18516. const x = clientX - deltaX;
  18517. const y = clientY - deltaY;
  18518. return {
  18519. x,
  18520. y
  18521. };
  18522. };
  18523. const isXYInContentArea = (editor, clientX, clientY) => {
  18524. const bodyElm = SugarElement.fromDom(editor.getBody());
  18525. const targetElm = editor.inline ? bodyElm : documentElement(bodyElm);
  18526. const transposedPoint = transpose(editor.inline, targetElm, clientX, clientY);
  18527. return isInsideElementContentArea(targetElm, transposedPoint.x, transposedPoint.y);
  18528. };
  18529. const fromDomSafe = node => Optional.from(node).map(SugarElement.fromDom);
  18530. const isEditorAttachedToDom = editor => {
  18531. const rawContainer = editor.inline ? editor.getBody() : editor.getContentAreaContainer();
  18532. return fromDomSafe(rawContainer).map(inBody).getOr(false);
  18533. };
  18534. var NotificationManagerImpl = () => {
  18535. const unimplemented = () => {
  18536. throw new Error('Theme did not provide a NotificationManager implementation.');
  18537. };
  18538. return {
  18539. open: unimplemented,
  18540. close: unimplemented,
  18541. getArgs: unimplemented
  18542. };
  18543. };
  18544. const NotificationManager = editor => {
  18545. const notifications = [];
  18546. const getImplementation = () => {
  18547. const theme = editor.theme;
  18548. return theme && theme.getNotificationManagerImpl ? theme.getNotificationManagerImpl() : NotificationManagerImpl();
  18549. };
  18550. const getTopNotification = () => {
  18551. return Optional.from(notifications[0]);
  18552. };
  18553. const isEqual = (a, b) => {
  18554. return a.type === b.type && a.text === b.text && !a.progressBar && !a.timeout && !b.progressBar && !b.timeout;
  18555. };
  18556. const reposition = () => {
  18557. each$e(notifications, notification => {
  18558. notification.reposition();
  18559. });
  18560. };
  18561. const addNotification = notification => {
  18562. notifications.push(notification);
  18563. };
  18564. const closeNotification = notification => {
  18565. findIndex$2(notifications, otherNotification => {
  18566. return otherNotification === notification;
  18567. }).each(index => {
  18568. notifications.splice(index, 1);
  18569. });
  18570. };
  18571. const open = (spec, fireEvent = true) => {
  18572. if (editor.removed || !isEditorAttachedToDom(editor)) {
  18573. return {};
  18574. }
  18575. if (fireEvent) {
  18576. editor.dispatch('BeforeOpenNotification', { notification: spec });
  18577. }
  18578. return find$2(notifications, notification => {
  18579. return isEqual(getImplementation().getArgs(notification), spec);
  18580. }).getOrThunk(() => {
  18581. editor.editorManager.setActive(editor);
  18582. const notification = getImplementation().open(spec, () => {
  18583. closeNotification(notification);
  18584. reposition();
  18585. getTopNotification().fold(() => editor.focus(), top => focus$1(SugarElement.fromDom(top.getEl())));
  18586. });
  18587. addNotification(notification);
  18588. reposition();
  18589. editor.dispatch('OpenNotification', { notification: { ...notification } });
  18590. return notification;
  18591. });
  18592. };
  18593. const close = () => {
  18594. getTopNotification().each(notification => {
  18595. getImplementation().close(notification);
  18596. closeNotification(notification);
  18597. reposition();
  18598. });
  18599. };
  18600. const getNotifications = constant(notifications);
  18601. const registerEvents = editor => {
  18602. editor.on('SkinLoaded', () => {
  18603. const serviceMessage = getServiceMessage(editor);
  18604. if (serviceMessage) {
  18605. open({
  18606. text: serviceMessage,
  18607. type: 'warning',
  18608. timeout: 0
  18609. }, false);
  18610. }
  18611. reposition();
  18612. });
  18613. editor.on('show ResizeEditor ResizeWindow NodeChange', () => {
  18614. requestAnimationFrame(reposition);
  18615. });
  18616. editor.on('remove', () => {
  18617. each$e(notifications.slice(), notification => {
  18618. getImplementation().close(notification);
  18619. });
  18620. });
  18621. };
  18622. registerEvents(editor);
  18623. return {
  18624. open,
  18625. close,
  18626. getNotifications
  18627. };
  18628. };
  18629. const PluginManager = AddOnManager.PluginManager;
  18630. const ThemeManager = AddOnManager.ThemeManager;
  18631. var WindowManagerImpl = () => {
  18632. const unimplemented = () => {
  18633. throw new Error('Theme did not provide a WindowManager implementation.');
  18634. };
  18635. return {
  18636. open: unimplemented,
  18637. openUrl: unimplemented,
  18638. alert: unimplemented,
  18639. confirm: unimplemented,
  18640. close: unimplemented
  18641. };
  18642. };
  18643. const WindowManager = editor => {
  18644. let dialogs = [];
  18645. const getImplementation = () => {
  18646. const theme = editor.theme;
  18647. return theme && theme.getWindowManagerImpl ? theme.getWindowManagerImpl() : WindowManagerImpl();
  18648. };
  18649. const funcBind = (scope, f) => {
  18650. return (...args) => {
  18651. return f ? f.apply(scope, args) : undefined;
  18652. };
  18653. };
  18654. const fireOpenEvent = dialog => {
  18655. editor.dispatch('OpenWindow', { dialog });
  18656. };
  18657. const fireCloseEvent = dialog => {
  18658. editor.dispatch('CloseWindow', { dialog });
  18659. };
  18660. const addDialog = dialog => {
  18661. dialogs.push(dialog);
  18662. fireOpenEvent(dialog);
  18663. };
  18664. const closeDialog = dialog => {
  18665. fireCloseEvent(dialog);
  18666. dialogs = filter$5(dialogs, otherDialog => {
  18667. return otherDialog !== dialog;
  18668. });
  18669. if (dialogs.length === 0) {
  18670. editor.focus();
  18671. }
  18672. };
  18673. const getTopDialog = () => {
  18674. return Optional.from(dialogs[dialogs.length - 1]);
  18675. };
  18676. const storeSelectionAndOpenDialog = openDialog => {
  18677. editor.editorManager.setActive(editor);
  18678. store(editor);
  18679. editor.ui.show();
  18680. const dialog = openDialog();
  18681. addDialog(dialog);
  18682. return dialog;
  18683. };
  18684. const open = (args, params) => {
  18685. return storeSelectionAndOpenDialog(() => getImplementation().open(args, params, closeDialog));
  18686. };
  18687. const openUrl = args => {
  18688. return storeSelectionAndOpenDialog(() => getImplementation().openUrl(args, closeDialog));
  18689. };
  18690. const alert = (message, callback, scope) => {
  18691. const windowManagerImpl = getImplementation();
  18692. windowManagerImpl.alert(message, funcBind(scope ? scope : windowManagerImpl, callback));
  18693. };
  18694. const confirm = (message, callback, scope) => {
  18695. const windowManagerImpl = getImplementation();
  18696. windowManagerImpl.confirm(message, funcBind(scope ? scope : windowManagerImpl, callback));
  18697. };
  18698. const close = () => {
  18699. getTopDialog().each(dialog => {
  18700. getImplementation().close(dialog);
  18701. closeDialog(dialog);
  18702. });
  18703. };
  18704. editor.on('remove', () => {
  18705. each$e(dialogs, dialog => {
  18706. getImplementation().close(dialog);
  18707. });
  18708. });
  18709. return {
  18710. open,
  18711. openUrl,
  18712. alert,
  18713. confirm,
  18714. close
  18715. };
  18716. };
  18717. const displayNotification = (editor, message) => {
  18718. editor.notificationManager.open({
  18719. type: 'error',
  18720. text: message
  18721. });
  18722. };
  18723. const displayError = (editor, message) => {
  18724. if (editor._skinLoaded) {
  18725. displayNotification(editor, message);
  18726. } else {
  18727. editor.on('SkinLoaded', () => {
  18728. displayNotification(editor, message);
  18729. });
  18730. }
  18731. };
  18732. const uploadError = (editor, message) => {
  18733. displayError(editor, I18n.translate([
  18734. 'Failed to upload image: {0}',
  18735. message
  18736. ]));
  18737. };
  18738. const logError = (editor, errorType, msg) => {
  18739. fireError(editor, errorType, { message: msg });
  18740. console.error(msg);
  18741. };
  18742. const createLoadError = (type, url, name) => name ? `Failed to load ${ type }: ${ name } from url ${ url }` : `Failed to load ${ type } url: ${ url }`;
  18743. const pluginLoadError = (editor, url, name) => {
  18744. logError(editor, 'PluginLoadError', createLoadError('plugin', url, name));
  18745. };
  18746. const iconsLoadError = (editor, url, name) => {
  18747. logError(editor, 'IconsLoadError', createLoadError('icons', url, name));
  18748. };
  18749. const languageLoadError = (editor, url, name) => {
  18750. logError(editor, 'LanguageLoadError', createLoadError('language', url, name));
  18751. };
  18752. const themeLoadError = (editor, url, name) => {
  18753. logError(editor, 'ThemeLoadError', createLoadError('theme', url, name));
  18754. };
  18755. const modelLoadError = (editor, url, name) => {
  18756. logError(editor, 'ModelLoadError', createLoadError('model', url, name));
  18757. };
  18758. const pluginInitError = (editor, name, err) => {
  18759. const message = I18n.translate([
  18760. 'Failed to initialize plugin: {0}',
  18761. name
  18762. ]);
  18763. fireError(editor, 'PluginLoadError', { message });
  18764. initError(message, err);
  18765. displayError(editor, message);
  18766. };
  18767. const initError = (message, ...x) => {
  18768. const console = window.console;
  18769. if (console) {
  18770. if (console.error) {
  18771. console.error(message, ...x);
  18772. } else {
  18773. console.log(message, ...x);
  18774. }
  18775. }
  18776. };
  18777. const isContentCssSkinName = url => /^[a-z0-9\-]+$/i.test(url);
  18778. const getContentCssUrls = editor => {
  18779. return transformToUrls(editor, getContentCss(editor));
  18780. };
  18781. const getFontCssUrls = editor => {
  18782. return transformToUrls(editor, getFontCss(editor));
  18783. };
  18784. const transformToUrls = (editor, cssLinks) => {
  18785. const skinUrl = editor.editorManager.baseURL + '/skins/content';
  18786. const suffix = editor.editorManager.suffix;
  18787. const contentCssFile = `content${ suffix }.css`;
  18788. return map$3(cssLinks, url => {
  18789. if (isContentCssSkinName(url) && !editor.inline) {
  18790. return `${ skinUrl }/${ url }/${ contentCssFile }`;
  18791. } else {
  18792. return editor.documentBaseURI.toAbsolute(url);
  18793. }
  18794. });
  18795. };
  18796. const appendContentCssFromSettings = editor => {
  18797. editor.contentCSS = editor.contentCSS.concat(getContentCssUrls(editor), getFontCssUrls(editor));
  18798. };
  18799. const filter$1 = always;
  18800. const bind$1 = (element, event, handler) => bind$2(element, event, filter$1, handler);
  18801. const getAllImages = elm => {
  18802. return elm ? from(elm.getElementsByTagName('img')) : [];
  18803. };
  18804. const ImageScanner = (uploadStatus, blobCache) => {
  18805. const cachedPromises = {};
  18806. const findAll = (elm, predicate = always) => {
  18807. const images = filter$5(getAllImages(elm), img => {
  18808. const src = img.src;
  18809. if (img.hasAttribute('data-mce-bogus')) {
  18810. return false;
  18811. }
  18812. if (img.hasAttribute('data-mce-placeholder')) {
  18813. return false;
  18814. }
  18815. if (!src || src === Env.transparentSrc) {
  18816. return false;
  18817. }
  18818. if (startsWith(src, 'blob:')) {
  18819. return !uploadStatus.isUploaded(src) && predicate(img);
  18820. }
  18821. if (startsWith(src, 'data:')) {
  18822. return predicate(img);
  18823. }
  18824. return false;
  18825. });
  18826. const promises = map$3(images, img => {
  18827. const imageSrc = img.src;
  18828. if (has$2(cachedPromises, imageSrc)) {
  18829. return cachedPromises[imageSrc].then(imageInfo => {
  18830. if (isString(imageInfo)) {
  18831. return imageInfo;
  18832. } else {
  18833. return {
  18834. image: img,
  18835. blobInfo: imageInfo.blobInfo
  18836. };
  18837. }
  18838. });
  18839. } else {
  18840. const newPromise = imageToBlobInfo(blobCache, imageSrc).then(blobInfo => {
  18841. delete cachedPromises[imageSrc];
  18842. return {
  18843. image: img,
  18844. blobInfo
  18845. };
  18846. }).catch(error => {
  18847. delete cachedPromises[imageSrc];
  18848. return error;
  18849. });
  18850. cachedPromises[imageSrc] = newPromise;
  18851. return newPromise;
  18852. }
  18853. });
  18854. return Promise.all(promises);
  18855. };
  18856. return { findAll };
  18857. };
  18858. const UploadStatus = () => {
  18859. const PENDING = 1, UPLOADED = 2;
  18860. let blobUriStatuses = {};
  18861. const createStatus = (status, resultUri) => {
  18862. return {
  18863. status,
  18864. resultUri
  18865. };
  18866. };
  18867. const hasBlobUri = blobUri => {
  18868. return blobUri in blobUriStatuses;
  18869. };
  18870. const getResultUri = blobUri => {
  18871. const result = blobUriStatuses[blobUri];
  18872. return result ? result.resultUri : null;
  18873. };
  18874. const isPending = blobUri => {
  18875. return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === PENDING : false;
  18876. };
  18877. const isUploaded = blobUri => {
  18878. return hasBlobUri(blobUri) ? blobUriStatuses[blobUri].status === UPLOADED : false;
  18879. };
  18880. const markPending = blobUri => {
  18881. blobUriStatuses[blobUri] = createStatus(PENDING, null);
  18882. };
  18883. const markUploaded = (blobUri, resultUri) => {
  18884. blobUriStatuses[blobUri] = createStatus(UPLOADED, resultUri);
  18885. };
  18886. const removeFailed = blobUri => {
  18887. delete blobUriStatuses[blobUri];
  18888. };
  18889. const destroy = () => {
  18890. blobUriStatuses = {};
  18891. };
  18892. return {
  18893. hasBlobUri,
  18894. getResultUri,
  18895. isPending,
  18896. isUploaded,
  18897. markPending,
  18898. markUploaded,
  18899. removeFailed,
  18900. destroy
  18901. };
  18902. };
  18903. let count = 0;
  18904. const seed = () => {
  18905. const rnd = () => {
  18906. return Math.round(Math.random() * 4294967295).toString(36);
  18907. };
  18908. const now = new Date().getTime();
  18909. return 's' + now.toString(36) + rnd() + rnd() + rnd();
  18910. };
  18911. const uuid = prefix => {
  18912. return prefix + count++ + seed();
  18913. };
  18914. const BlobCache = () => {
  18915. let cache = [];
  18916. const mimeToExt = mime => {
  18917. const mimes = {
  18918. 'image/jpeg': 'jpg',
  18919. 'image/jpg': 'jpg',
  18920. 'image/gif': 'gif',
  18921. 'image/png': 'png',
  18922. 'image/apng': 'apng',
  18923. 'image/avif': 'avif',
  18924. 'image/svg+xml': 'svg',
  18925. 'image/webp': 'webp',
  18926. 'image/bmp': 'bmp',
  18927. 'image/tiff': 'tiff'
  18928. };
  18929. return mimes[mime.toLowerCase()] || 'dat';
  18930. };
  18931. const create = (o, blob, base64, name, filename) => {
  18932. if (isString(o)) {
  18933. const id = o;
  18934. return toBlobInfo({
  18935. id,
  18936. name,
  18937. filename,
  18938. blob: blob,
  18939. base64: base64
  18940. });
  18941. } else if (isObject(o)) {
  18942. return toBlobInfo(o);
  18943. } else {
  18944. throw new Error('Unknown input type');
  18945. }
  18946. };
  18947. const toBlobInfo = o => {
  18948. if (!o.blob || !o.base64) {
  18949. throw new Error('blob and base64 representations of the image are required for BlobInfo to be created');
  18950. }
  18951. const id = o.id || uuid('blobid');
  18952. const name = o.name || id;
  18953. const blob = o.blob;
  18954. return {
  18955. id: constant(id),
  18956. name: constant(name),
  18957. filename: constant(o.filename || name + '.' + mimeToExt(blob.type)),
  18958. blob: constant(blob),
  18959. base64: constant(o.base64),
  18960. blobUri: constant(o.blobUri || URL.createObjectURL(blob)),
  18961. uri: constant(o.uri)
  18962. };
  18963. };
  18964. const add = blobInfo => {
  18965. if (!get(blobInfo.id())) {
  18966. cache.push(blobInfo);
  18967. }
  18968. };
  18969. const findFirst = predicate => find$2(cache, predicate).getOrUndefined();
  18970. const get = id => findFirst(cachedBlobInfo => cachedBlobInfo.id() === id);
  18971. const getByUri = blobUri => findFirst(blobInfo => blobInfo.blobUri() === blobUri);
  18972. const getByData = (base64, type) => findFirst(blobInfo => blobInfo.base64() === base64 && blobInfo.blob().type === type);
  18973. const removeByUri = blobUri => {
  18974. cache = filter$5(cache, blobInfo => {
  18975. if (blobInfo.blobUri() === blobUri) {
  18976. URL.revokeObjectURL(blobInfo.blobUri());
  18977. return false;
  18978. }
  18979. return true;
  18980. });
  18981. };
  18982. const destroy = () => {
  18983. each$e(cache, cachedBlobInfo => {
  18984. URL.revokeObjectURL(cachedBlobInfo.blobUri());
  18985. });
  18986. cache = [];
  18987. };
  18988. return {
  18989. create,
  18990. add,
  18991. get,
  18992. getByUri,
  18993. getByData,
  18994. findFirst,
  18995. removeByUri,
  18996. destroy
  18997. };
  18998. };
  18999. const Uploader = (uploadStatus, settings) => {
  19000. const pendingPromises = {};
  19001. const pathJoin = (path1, path2) => {
  19002. if (path1) {
  19003. return path1.replace(/\/$/, '') + '/' + path2.replace(/^\//, '');
  19004. }
  19005. return path2;
  19006. };
  19007. const defaultHandler = (blobInfo, progress) => new Promise((success, failure) => {
  19008. const xhr = new XMLHttpRequest();
  19009. xhr.open('POST', settings.url);
  19010. xhr.withCredentials = settings.credentials;
  19011. xhr.upload.onprogress = e => {
  19012. progress(e.loaded / e.total * 100);
  19013. };
  19014. xhr.onerror = () => {
  19015. failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
  19016. };
  19017. xhr.onload = () => {
  19018. if (xhr.status < 200 || xhr.status >= 300) {
  19019. failure('HTTP Error: ' + xhr.status);
  19020. return;
  19021. }
  19022. const json = JSON.parse(xhr.responseText);
  19023. if (!json || !isString(json.location)) {
  19024. failure('Invalid JSON: ' + xhr.responseText);
  19025. return;
  19026. }
  19027. success(pathJoin(settings.basePath, json.location));
  19028. };
  19029. const formData = new FormData();
  19030. formData.append('file', blobInfo.blob(), blobInfo.filename());
  19031. xhr.send(formData);
  19032. });
  19033. const uploadHandler = isFunction(settings.handler) ? settings.handler : defaultHandler;
  19034. const noUpload = () => new Promise(resolve => {
  19035. resolve([]);
  19036. });
  19037. const handlerSuccess = (blobInfo, url) => ({
  19038. url,
  19039. blobInfo,
  19040. status: true
  19041. });
  19042. const handlerFailure = (blobInfo, error) => ({
  19043. url: '',
  19044. blobInfo,
  19045. status: false,
  19046. error
  19047. });
  19048. const resolvePending = (blobUri, result) => {
  19049. Tools.each(pendingPromises[blobUri], resolve => {
  19050. resolve(result);
  19051. });
  19052. delete pendingPromises[blobUri];
  19053. };
  19054. const uploadBlobInfo = (blobInfo, handler, openNotification) => {
  19055. uploadStatus.markPending(blobInfo.blobUri());
  19056. return new Promise(resolve => {
  19057. let notification;
  19058. let progress;
  19059. try {
  19060. const closeNotification = () => {
  19061. if (notification) {
  19062. notification.close();
  19063. progress = noop;
  19064. }
  19065. };
  19066. const success = url => {
  19067. closeNotification();
  19068. uploadStatus.markUploaded(blobInfo.blobUri(), url);
  19069. resolvePending(blobInfo.blobUri(), handlerSuccess(blobInfo, url));
  19070. resolve(handlerSuccess(blobInfo, url));
  19071. };
  19072. const failure = error => {
  19073. closeNotification();
  19074. uploadStatus.removeFailed(blobInfo.blobUri());
  19075. resolvePending(blobInfo.blobUri(), handlerFailure(blobInfo, error));
  19076. resolve(handlerFailure(blobInfo, error));
  19077. };
  19078. progress = percent => {
  19079. if (percent < 0 || percent > 100) {
  19080. return;
  19081. }
  19082. Optional.from(notification).orThunk(() => Optional.from(openNotification).map(apply$1)).each(n => {
  19083. notification = n;
  19084. n.progressBar.value(percent);
  19085. });
  19086. };
  19087. handler(blobInfo, progress).then(success, err => {
  19088. failure(isString(err) ? { message: err } : err);
  19089. });
  19090. } catch (ex) {
  19091. resolve(handlerFailure(blobInfo, ex));
  19092. }
  19093. });
  19094. };
  19095. const isDefaultHandler = handler => handler === defaultHandler;
  19096. const pendingUploadBlobInfo = blobInfo => {
  19097. const blobUri = blobInfo.blobUri();
  19098. return new Promise(resolve => {
  19099. pendingPromises[blobUri] = pendingPromises[blobUri] || [];
  19100. pendingPromises[blobUri].push(resolve);
  19101. });
  19102. };
  19103. const uploadBlobs = (blobInfos, openNotification) => {
  19104. blobInfos = Tools.grep(blobInfos, blobInfo => !uploadStatus.isUploaded(blobInfo.blobUri()));
  19105. return Promise.all(Tools.map(blobInfos, blobInfo => uploadStatus.isPending(blobInfo.blobUri()) ? pendingUploadBlobInfo(blobInfo) : uploadBlobInfo(blobInfo, uploadHandler, openNotification)));
  19106. };
  19107. const upload = (blobInfos, openNotification) => !settings.url && isDefaultHandler(uploadHandler) ? noUpload() : uploadBlobs(blobInfos, openNotification);
  19108. return { upload };
  19109. };
  19110. const openNotification = editor => () => editor.notificationManager.open({
  19111. text: editor.translate('Image uploading...'),
  19112. type: 'info',
  19113. timeout: -1,
  19114. progressBar: true
  19115. });
  19116. const createUploader = (editor, uploadStatus) => Uploader(uploadStatus, {
  19117. url: getImageUploadUrl(editor),
  19118. basePath: getImageUploadBasePath(editor),
  19119. credentials: getImagesUploadCredentials(editor),
  19120. handler: getImagesUploadHandler(editor)
  19121. });
  19122. const ImageUploader = editor => {
  19123. const uploadStatus = UploadStatus();
  19124. const uploader = createUploader(editor, uploadStatus);
  19125. return { upload: (blobInfos, showNotification = true) => uploader.upload(blobInfos, showNotification ? openNotification(editor) : undefined) };
  19126. };
  19127. const EditorUpload = editor => {
  19128. const blobCache = BlobCache();
  19129. let uploader, imageScanner;
  19130. const uploadStatus = UploadStatus();
  19131. const urlFilters = [];
  19132. const aliveGuard = callback => {
  19133. return result => {
  19134. if (editor.selection) {
  19135. return callback(result);
  19136. }
  19137. return [];
  19138. };
  19139. };
  19140. const cacheInvalidator = url => url + (url.indexOf('?') === -1 ? '?' : '&') + new Date().getTime();
  19141. const replaceString = (content, search, replace) => {
  19142. let index = 0;
  19143. do {
  19144. index = content.indexOf(search, index);
  19145. if (index !== -1) {
  19146. content = content.substring(0, index) + replace + content.substr(index + search.length);
  19147. index += replace.length - search.length + 1;
  19148. }
  19149. } while (index !== -1);
  19150. return content;
  19151. };
  19152. const replaceImageUrl = (content, targetUrl, replacementUrl) => {
  19153. const replacementString = `src="${ replacementUrl }"${ replacementUrl === Env.transparentSrc ? ' data-mce-placeholder="1"' : '' }`;
  19154. content = replaceString(content, `src="${ targetUrl }"`, replacementString);
  19155. content = replaceString(content, 'data-mce-src="' + targetUrl + '"', 'data-mce-src="' + replacementUrl + '"');
  19156. return content;
  19157. };
  19158. const replaceUrlInUndoStack = (targetUrl, replacementUrl) => {
  19159. each$e(editor.undoManager.data, level => {
  19160. if (level.type === 'fragmented') {
  19161. level.fragments = map$3(level.fragments, fragment => replaceImageUrl(fragment, targetUrl, replacementUrl));
  19162. } else {
  19163. level.content = replaceImageUrl(level.content, targetUrl, replacementUrl);
  19164. }
  19165. });
  19166. };
  19167. const replaceImageUriInView = (image, resultUri) => {
  19168. const src = editor.convertURL(resultUri, 'src');
  19169. replaceUrlInUndoStack(image.src, resultUri);
  19170. setAll$1(SugarElement.fromDom(image), {
  19171. 'src': shouldReuseFileName(editor) ? cacheInvalidator(resultUri) : resultUri,
  19172. 'data-mce-src': src
  19173. });
  19174. };
  19175. const uploadImages = () => {
  19176. if (!uploader) {
  19177. uploader = createUploader(editor, uploadStatus);
  19178. }
  19179. return scanForImages().then(aliveGuard(imageInfos => {
  19180. const blobInfos = map$3(imageInfos, imageInfo => imageInfo.blobInfo);
  19181. return uploader.upload(blobInfos, openNotification(editor)).then(aliveGuard(result => {
  19182. const imagesToRemove = [];
  19183. let shouldDispatchChange = false;
  19184. const filteredResult = map$3(result, (uploadInfo, index) => {
  19185. const {blobInfo, image} = imageInfos[index];
  19186. let removed = false;
  19187. if (uploadInfo.status && shouldReplaceBlobUris(editor)) {
  19188. if (uploadInfo.url && !contains$1(image.src, uploadInfo.url)) {
  19189. shouldDispatchChange = true;
  19190. }
  19191. blobCache.removeByUri(image.src);
  19192. if (isRtc(editor)) ; else {
  19193. replaceImageUriInView(image, uploadInfo.url);
  19194. }
  19195. } else if (uploadInfo.error) {
  19196. if (uploadInfo.error.remove) {
  19197. replaceUrlInUndoStack(image.src, Env.transparentSrc);
  19198. imagesToRemove.push(image);
  19199. removed = true;
  19200. }
  19201. uploadError(editor, uploadInfo.error.message);
  19202. }
  19203. return {
  19204. element: image,
  19205. status: uploadInfo.status,
  19206. uploadUri: uploadInfo.url,
  19207. blobInfo,
  19208. removed
  19209. };
  19210. });
  19211. if (imagesToRemove.length > 0 && !isRtc(editor)) {
  19212. editor.undoManager.transact(() => {
  19213. each$e(imagesToRemove, element => {
  19214. editor.dom.remove(element);
  19215. blobCache.removeByUri(element.src);
  19216. });
  19217. });
  19218. } else if (shouldDispatchChange) {
  19219. editor.undoManager.dispatchChange();
  19220. }
  19221. return filteredResult;
  19222. }));
  19223. }));
  19224. };
  19225. const uploadImagesAuto = () => isAutomaticUploadsEnabled(editor) ? uploadImages() : Promise.resolve([]);
  19226. const isValidDataUriImage = imgElm => forall(urlFilters, filter => filter(imgElm));
  19227. const addFilter = filter => {
  19228. urlFilters.push(filter);
  19229. };
  19230. const scanForImages = () => {
  19231. if (!imageScanner) {
  19232. imageScanner = ImageScanner(uploadStatus, blobCache);
  19233. }
  19234. return imageScanner.findAll(editor.getBody(), isValidDataUriImage).then(aliveGuard(result => {
  19235. const filteredResult = filter$5(result, resultItem => {
  19236. if (isString(resultItem)) {
  19237. displayError(editor, resultItem);
  19238. return false;
  19239. } else {
  19240. return true;
  19241. }
  19242. });
  19243. if (isRtc(editor)) ; else {
  19244. each$e(filteredResult, resultItem => {
  19245. replaceUrlInUndoStack(resultItem.image.src, resultItem.blobInfo.blobUri());
  19246. resultItem.image.src = resultItem.blobInfo.blobUri();
  19247. resultItem.image.removeAttribute('data-mce-src');
  19248. });
  19249. }
  19250. return filteredResult;
  19251. }));
  19252. };
  19253. const destroy = () => {
  19254. blobCache.destroy();
  19255. uploadStatus.destroy();
  19256. imageScanner = uploader = null;
  19257. };
  19258. const replaceBlobUris = content => {
  19259. return content.replace(/src="(blob:[^"]+)"/g, (match, blobUri) => {
  19260. const resultUri = uploadStatus.getResultUri(blobUri);
  19261. if (resultUri) {
  19262. return 'src="' + resultUri + '"';
  19263. }
  19264. let blobInfo = blobCache.getByUri(blobUri);
  19265. if (!blobInfo) {
  19266. blobInfo = foldl(editor.editorManager.get(), (result, editor) => {
  19267. return result || editor.editorUpload && editor.editorUpload.blobCache.getByUri(blobUri);
  19268. }, undefined);
  19269. }
  19270. if (blobInfo) {
  19271. const blob = blobInfo.blob();
  19272. return 'src="data:' + blob.type + ';base64,' + blobInfo.base64() + '"';
  19273. }
  19274. return match;
  19275. });
  19276. };
  19277. editor.on('SetContent', () => {
  19278. if (isAutomaticUploadsEnabled(editor)) {
  19279. uploadImagesAuto();
  19280. } else {
  19281. scanForImages();
  19282. }
  19283. });
  19284. editor.on('RawSaveContent', e => {
  19285. e.content = replaceBlobUris(e.content);
  19286. });
  19287. editor.on('GetContent', e => {
  19288. if (e.source_view || e.format === 'raw' || e.format === 'tree') {
  19289. return;
  19290. }
  19291. e.content = replaceBlobUris(e.content);
  19292. });
  19293. editor.on('PostRender', () => {
  19294. editor.parser.addNodeFilter('img', images => {
  19295. each$e(images, img => {
  19296. const src = img.attr('src');
  19297. if (!src || blobCache.getByUri(src)) {
  19298. return;
  19299. }
  19300. const resultUri = uploadStatus.getResultUri(src);
  19301. if (resultUri) {
  19302. img.attr('src', resultUri);
  19303. }
  19304. });
  19305. });
  19306. });
  19307. return {
  19308. blobCache,
  19309. addFilter,
  19310. uploadImages,
  19311. uploadImagesAuto,
  19312. scanForImages,
  19313. destroy
  19314. };
  19315. };
  19316. const get$1 = editor => {
  19317. const dom = editor.dom;
  19318. const schemaType = editor.schema.type;
  19319. const formats = {
  19320. valigntop: [{
  19321. selector: 'td,th',
  19322. styles: { verticalAlign: 'top' }
  19323. }],
  19324. valignmiddle: [{
  19325. selector: 'td,th',
  19326. styles: { verticalAlign: 'middle' }
  19327. }],
  19328. valignbottom: [{
  19329. selector: 'td,th',
  19330. styles: { verticalAlign: 'bottom' }
  19331. }],
  19332. alignleft: [
  19333. {
  19334. selector: 'figure.image',
  19335. collapsed: false,
  19336. classes: 'align-left',
  19337. ceFalseOverride: true,
  19338. preview: 'font-family font-size'
  19339. },
  19340. {
  19341. selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
  19342. styles: { textAlign: 'left' },
  19343. inherit: false,
  19344. preview: false
  19345. },
  19346. {
  19347. selector: 'img,audio,video',
  19348. collapsed: false,
  19349. styles: { float: 'left' },
  19350. preview: 'font-family font-size'
  19351. },
  19352. {
  19353. selector: 'table',
  19354. collapsed: false,
  19355. styles: {
  19356. marginLeft: '0px',
  19357. marginRight: 'auto'
  19358. },
  19359. onformat: table => {
  19360. dom.setStyle(table, 'float', null);
  19361. },
  19362. preview: 'font-family font-size'
  19363. },
  19364. {
  19365. selector: '.mce-preview-object,[data-ephox-embed-iri]',
  19366. ceFalseOverride: true,
  19367. styles: { float: 'left' }
  19368. }
  19369. ],
  19370. aligncenter: [
  19371. {
  19372. selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
  19373. styles: { textAlign: 'center' },
  19374. inherit: false,
  19375. preview: 'font-family font-size'
  19376. },
  19377. {
  19378. selector: 'figure.image',
  19379. collapsed: false,
  19380. classes: 'align-center',
  19381. ceFalseOverride: true,
  19382. preview: 'font-family font-size'
  19383. },
  19384. {
  19385. selector: 'img,audio,video',
  19386. collapsed: false,
  19387. styles: {
  19388. display: 'block',
  19389. marginLeft: 'auto',
  19390. marginRight: 'auto'
  19391. },
  19392. preview: false
  19393. },
  19394. {
  19395. selector: 'table',
  19396. collapsed: false,
  19397. styles: {
  19398. marginLeft: 'auto',
  19399. marginRight: 'auto'
  19400. },
  19401. preview: 'font-family font-size'
  19402. },
  19403. {
  19404. selector: '.mce-preview-object',
  19405. ceFalseOverride: true,
  19406. styles: {
  19407. display: 'table',
  19408. marginLeft: 'auto',
  19409. marginRight: 'auto'
  19410. },
  19411. preview: false
  19412. },
  19413. {
  19414. selector: '[data-ephox-embed-iri]',
  19415. ceFalseOverride: true,
  19416. styles: {
  19417. marginLeft: 'auto',
  19418. marginRight: 'auto'
  19419. },
  19420. preview: false
  19421. }
  19422. ],
  19423. alignright: [
  19424. {
  19425. selector: 'figure.image',
  19426. collapsed: false,
  19427. classes: 'align-right',
  19428. ceFalseOverride: true,
  19429. preview: 'font-family font-size'
  19430. },
  19431. {
  19432. selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
  19433. styles: { textAlign: 'right' },
  19434. inherit: false,
  19435. preview: 'font-family font-size'
  19436. },
  19437. {
  19438. selector: 'img,audio,video',
  19439. collapsed: false,
  19440. styles: { float: 'right' },
  19441. preview: 'font-family font-size'
  19442. },
  19443. {
  19444. selector: 'table',
  19445. collapsed: false,
  19446. styles: {
  19447. marginRight: '0px',
  19448. marginLeft: 'auto'
  19449. },
  19450. onformat: table => {
  19451. dom.setStyle(table, 'float', null);
  19452. },
  19453. preview: 'font-family font-size'
  19454. },
  19455. {
  19456. selector: '.mce-preview-object,[data-ephox-embed-iri]',
  19457. ceFalseOverride: true,
  19458. styles: { float: 'right' },
  19459. preview: false
  19460. }
  19461. ],
  19462. alignjustify: [{
  19463. selector: 'figure,p,h1,h2,h3,h4,h5,h6,td,th,tr,div,ul,ol,li,pre',
  19464. styles: { textAlign: 'justify' },
  19465. inherit: false,
  19466. preview: 'font-family font-size'
  19467. }],
  19468. bold: [
  19469. {
  19470. inline: 'strong',
  19471. remove: 'all',
  19472. preserve_attributes: [
  19473. 'class',
  19474. 'style'
  19475. ]
  19476. },
  19477. {
  19478. inline: 'span',
  19479. styles: { fontWeight: 'bold' }
  19480. },
  19481. {
  19482. inline: 'b',
  19483. remove: 'all',
  19484. preserve_attributes: [
  19485. 'class',
  19486. 'style'
  19487. ]
  19488. }
  19489. ],
  19490. italic: [
  19491. {
  19492. inline: 'em',
  19493. remove: 'all',
  19494. preserve_attributes: [
  19495. 'class',
  19496. 'style'
  19497. ]
  19498. },
  19499. {
  19500. inline: 'span',
  19501. styles: { fontStyle: 'italic' }
  19502. },
  19503. {
  19504. inline: 'i',
  19505. remove: 'all',
  19506. preserve_attributes: [
  19507. 'class',
  19508. 'style'
  19509. ]
  19510. }
  19511. ],
  19512. underline: [
  19513. {
  19514. inline: 'span',
  19515. styles: { textDecoration: 'underline' },
  19516. exact: true
  19517. },
  19518. {
  19519. inline: 'u',
  19520. remove: 'all',
  19521. preserve_attributes: [
  19522. 'class',
  19523. 'style'
  19524. ]
  19525. }
  19526. ],
  19527. strikethrough: (() => {
  19528. const span = {
  19529. inline: 'span',
  19530. styles: { textDecoration: 'line-through' },
  19531. exact: true
  19532. };
  19533. const strike = {
  19534. inline: 'strike',
  19535. remove: 'all',
  19536. preserve_attributes: [
  19537. 'class',
  19538. 'style'
  19539. ]
  19540. };
  19541. const s = {
  19542. inline: 's',
  19543. remove: 'all',
  19544. preserve_attributes: [
  19545. 'class',
  19546. 'style'
  19547. ]
  19548. };
  19549. return schemaType !== 'html4' ? [
  19550. s,
  19551. span,
  19552. strike
  19553. ] : [
  19554. span,
  19555. s,
  19556. strike
  19557. ];
  19558. })(),
  19559. forecolor: {
  19560. inline: 'span',
  19561. styles: { color: '%value' },
  19562. links: true,
  19563. remove_similar: true,
  19564. clear_child_styles: true
  19565. },
  19566. hilitecolor: {
  19567. inline: 'span',
  19568. styles: { backgroundColor: '%value' },
  19569. links: true,
  19570. remove_similar: true,
  19571. clear_child_styles: true
  19572. },
  19573. fontname: {
  19574. inline: 'span',
  19575. toggle: false,
  19576. styles: { fontFamily: '%value' },
  19577. clear_child_styles: true
  19578. },
  19579. fontsize: {
  19580. inline: 'span',
  19581. toggle: false,
  19582. styles: { fontSize: '%value' },
  19583. clear_child_styles: true
  19584. },
  19585. lineheight: {
  19586. selector: 'h1,h2,h3,h4,h5,h6,p,li,td,th,div',
  19587. styles: { lineHeight: '%value' }
  19588. },
  19589. fontsize_class: {
  19590. inline: 'span',
  19591. attributes: { class: '%value' }
  19592. },
  19593. blockquote: {
  19594. block: 'blockquote',
  19595. wrapper: true,
  19596. remove: 'all'
  19597. },
  19598. subscript: { inline: 'sub' },
  19599. superscript: { inline: 'sup' },
  19600. code: { inline: 'code' },
  19601. link: {
  19602. inline: 'a',
  19603. selector: 'a',
  19604. remove: 'all',
  19605. split: true,
  19606. deep: true,
  19607. onmatch: (node, _fmt, _itemName) => {
  19608. return isElement$6(node) && node.hasAttribute('href');
  19609. },
  19610. onformat: (elm, _fmt, vars) => {
  19611. Tools.each(vars, (value, key) => {
  19612. dom.setAttrib(elm, key, value);
  19613. });
  19614. }
  19615. },
  19616. lang: {
  19617. inline: 'span',
  19618. clear_child_styles: true,
  19619. remove_similar: true,
  19620. attributes: {
  19621. 'lang': '%value',
  19622. 'data-mce-lang': vars => {
  19623. var _a;
  19624. return (_a = vars === null || vars === void 0 ? void 0 : vars.customValue) !== null && _a !== void 0 ? _a : null;
  19625. }
  19626. }
  19627. },
  19628. removeformat: [
  19629. {
  19630. selector: 'b,strong,em,i,font,u,strike,s,sub,sup,dfn,code,samp,kbd,var,cite,mark,q,del,ins,small',
  19631. remove: 'all',
  19632. split: true,
  19633. expand: false,
  19634. block_expand: true,
  19635. deep: true
  19636. },
  19637. {
  19638. selector: 'span',
  19639. attributes: [
  19640. 'style',
  19641. 'class'
  19642. ],
  19643. remove: 'empty',
  19644. split: true,
  19645. expand: false,
  19646. deep: true
  19647. },
  19648. {
  19649. selector: '*',
  19650. attributes: [
  19651. 'style',
  19652. 'class'
  19653. ],
  19654. split: false,
  19655. expand: false,
  19656. deep: true
  19657. }
  19658. ]
  19659. };
  19660. Tools.each('p h1 h2 h3 h4 h5 h6 div address pre dt dd samp'.split(/\s/), name => {
  19661. formats[name] = {
  19662. block: name,
  19663. remove: 'all'
  19664. };
  19665. });
  19666. return formats;
  19667. };
  19668. const genericBase = {
  19669. remove_similar: true,
  19670. inherit: false
  19671. };
  19672. const cellBase = {
  19673. selector: 'td,th',
  19674. ...genericBase
  19675. };
  19676. const cellFormats = {
  19677. tablecellbackgroundcolor: {
  19678. styles: { backgroundColor: '%value' },
  19679. ...cellBase
  19680. },
  19681. tablecellverticalalign: {
  19682. styles: { 'vertical-align': '%value' },
  19683. ...cellBase
  19684. },
  19685. tablecellbordercolor: {
  19686. styles: { borderColor: '%value' },
  19687. ...cellBase
  19688. },
  19689. tablecellclass: {
  19690. classes: ['%value'],
  19691. ...cellBase
  19692. },
  19693. tableclass: {
  19694. selector: 'table',
  19695. classes: ['%value'],
  19696. ...genericBase
  19697. },
  19698. tablecellborderstyle: {
  19699. styles: { borderStyle: '%value' },
  19700. ...cellBase
  19701. },
  19702. tablecellborderwidth: {
  19703. styles: { borderWidth: '%value' },
  19704. ...cellBase
  19705. }
  19706. };
  19707. const get = constant(cellFormats);
  19708. const FormatRegistry = editor => {
  19709. const formats = {};
  19710. const get$2 = name => isNonNullable(name) ? formats[name] : formats;
  19711. const has = name => has$2(formats, name);
  19712. const register = (name, format) => {
  19713. if (name) {
  19714. if (!isString(name)) {
  19715. each$d(name, (format, name) => {
  19716. register(name, format);
  19717. });
  19718. } else {
  19719. if (!isArray$1(format)) {
  19720. format = [format];
  19721. }
  19722. each$e(format, format => {
  19723. if (isUndefined(format.deep)) {
  19724. format.deep = !isSelectorFormat(format);
  19725. }
  19726. if (isUndefined(format.split)) {
  19727. format.split = !isSelectorFormat(format) || isInlineFormat(format);
  19728. }
  19729. if (isUndefined(format.remove) && isSelectorFormat(format) && !isInlineFormat(format)) {
  19730. format.remove = 'none';
  19731. }
  19732. if (isSelectorFormat(format) && isInlineFormat(format)) {
  19733. format.mixed = true;
  19734. format.block_expand = true;
  19735. }
  19736. if (isString(format.classes)) {
  19737. format.classes = format.classes.split(/\s+/);
  19738. }
  19739. });
  19740. formats[name] = format;
  19741. }
  19742. }
  19743. };
  19744. const unregister = name => {
  19745. if (name && formats[name]) {
  19746. delete formats[name];
  19747. }
  19748. return formats;
  19749. };
  19750. register(get$1(editor));
  19751. register(get());
  19752. register(getFormats(editor));
  19753. return {
  19754. get: get$2,
  19755. has,
  19756. register,
  19757. unregister
  19758. };
  19759. };
  19760. const each$3 = Tools.each;
  19761. const dom = DOMUtils.DOM;
  19762. const isPreviewItem = item => isNonNullable(item) && isObject(item);
  19763. const parsedSelectorToHtml = (ancestry, editor) => {
  19764. const schema = editor && editor.schema || Schema({});
  19765. const decorate = (elm, item) => {
  19766. if (item.classes.length > 0) {
  19767. dom.addClass(elm, item.classes.join(' '));
  19768. }
  19769. dom.setAttribs(elm, item.attrs);
  19770. };
  19771. const createElement = sItem => {
  19772. const item = isString(sItem) ? {
  19773. name: sItem,
  19774. classes: [],
  19775. attrs: {}
  19776. } : sItem;
  19777. const elm = dom.create(item.name);
  19778. decorate(elm, item);
  19779. return elm;
  19780. };
  19781. const getRequiredParent = (elm, candidate) => {
  19782. const elmRule = schema.getElementRule(elm.nodeName.toLowerCase());
  19783. const parentsRequired = elmRule === null || elmRule === void 0 ? void 0 : elmRule.parentsRequired;
  19784. if (parentsRequired && parentsRequired.length) {
  19785. return candidate && contains$2(parentsRequired, candidate) ? candidate : parentsRequired[0];
  19786. } else {
  19787. return false;
  19788. }
  19789. };
  19790. const wrapInHtml = (elm, ancestors, siblings) => {
  19791. let parentCandidate;
  19792. const ancestor = ancestors[0];
  19793. const ancestorName = isPreviewItem(ancestor) ? ancestor.name : undefined;
  19794. const parentRequired = getRequiredParent(elm, ancestorName);
  19795. if (parentRequired) {
  19796. if (ancestorName === parentRequired) {
  19797. parentCandidate = ancestor;
  19798. ancestors = ancestors.slice(1);
  19799. } else {
  19800. parentCandidate = parentRequired;
  19801. }
  19802. } else if (ancestor) {
  19803. parentCandidate = ancestor;
  19804. ancestors = ancestors.slice(1);
  19805. } else if (!siblings) {
  19806. return elm;
  19807. }
  19808. const parent = parentCandidate ? createElement(parentCandidate) : dom.create('div');
  19809. parent.appendChild(elm);
  19810. if (siblings) {
  19811. Tools.each(siblings, sibling => {
  19812. const siblingElm = createElement(sibling);
  19813. parent.insertBefore(siblingElm, elm);
  19814. });
  19815. }
  19816. const parentSiblings = isPreviewItem(parentCandidate) ? parentCandidate.siblings : undefined;
  19817. return wrapInHtml(parent, ancestors, parentSiblings);
  19818. };
  19819. const fragment = dom.create('div');
  19820. if (ancestry.length > 0) {
  19821. const item = ancestry[0];
  19822. const elm = createElement(item);
  19823. const siblings = isPreviewItem(item) ? item.siblings : undefined;
  19824. fragment.appendChild(wrapInHtml(elm, ancestry.slice(1), siblings));
  19825. }
  19826. return fragment;
  19827. };
  19828. const parseSelectorItem = item => {
  19829. item = Tools.trim(item);
  19830. let tagName = 'div';
  19831. const obj = {
  19832. name: tagName,
  19833. classes: [],
  19834. attrs: {},
  19835. selector: item
  19836. };
  19837. if (item !== '*') {
  19838. tagName = item.replace(/(?:([#\.]|::?)([\w\-]+)|(\[)([^\]]+)\]?)/g, ($0, $1, $2, $3, $4) => {
  19839. switch ($1) {
  19840. case '#':
  19841. obj.attrs.id = $2;
  19842. break;
  19843. case '.':
  19844. obj.classes.push($2);
  19845. break;
  19846. case ':':
  19847. if (Tools.inArray('checked disabled enabled read-only required'.split(' '), $2) !== -1) {
  19848. obj.attrs[$2] = $2;
  19849. }
  19850. break;
  19851. }
  19852. if ($3 === '[') {
  19853. const m = $4.match(/([\w\-]+)(?:\=\"([^\"]+))?/);
  19854. if (m) {
  19855. obj.attrs[m[1]] = m[2];
  19856. }
  19857. }
  19858. return '';
  19859. });
  19860. }
  19861. obj.name = tagName || 'div';
  19862. return obj;
  19863. };
  19864. const parseSelector = selector => {
  19865. if (!isString(selector)) {
  19866. return [];
  19867. }
  19868. selector = selector.split(/\s*,\s*/)[0];
  19869. selector = selector.replace(/\s*(~\+|~|\+|>)\s*/g, '$1');
  19870. return Tools.map(selector.split(/(?:>|\s+(?![^\[\]]+\]))/), item => {
  19871. const siblings = Tools.map(item.split(/(?:~\+|~|\+)/), parseSelectorItem);
  19872. const obj = siblings.pop();
  19873. if (siblings.length) {
  19874. obj.siblings = siblings;
  19875. }
  19876. return obj;
  19877. }).reverse();
  19878. };
  19879. const getCssText = (editor, format) => {
  19880. let previewCss = '';
  19881. let previewStyles = getPreviewStyles(editor);
  19882. if (previewStyles === '') {
  19883. return '';
  19884. }
  19885. const removeVars = val => {
  19886. return isString(val) ? val.replace(/%(\w+)/g, '') : '';
  19887. };
  19888. const getComputedStyle = (name, elm) => {
  19889. return dom.getStyle(elm !== null && elm !== void 0 ? elm : editor.getBody(), name, true);
  19890. };
  19891. if (isString(format)) {
  19892. const formats = editor.formatter.get(format);
  19893. if (!formats) {
  19894. return '';
  19895. }
  19896. format = formats[0];
  19897. }
  19898. if ('preview' in format) {
  19899. const preview = format.preview;
  19900. if (preview === false) {
  19901. return '';
  19902. } else {
  19903. previewStyles = preview || previewStyles;
  19904. }
  19905. }
  19906. let name = format.block || format.inline || 'span';
  19907. let previewFrag;
  19908. const items = parseSelector(format.selector);
  19909. if (items.length > 0) {
  19910. if (!items[0].name) {
  19911. items[0].name = name;
  19912. }
  19913. name = format.selector;
  19914. previewFrag = parsedSelectorToHtml(items, editor);
  19915. } else {
  19916. previewFrag = parsedSelectorToHtml([name], editor);
  19917. }
  19918. const previewElm = dom.select(name, previewFrag)[0] || previewFrag.firstChild;
  19919. each$3(format.styles, (value, name) => {
  19920. const newValue = removeVars(value);
  19921. if (newValue) {
  19922. dom.setStyle(previewElm, name, newValue);
  19923. }
  19924. });
  19925. each$3(format.attributes, (value, name) => {
  19926. const newValue = removeVars(value);
  19927. if (newValue) {
  19928. dom.setAttrib(previewElm, name, newValue);
  19929. }
  19930. });
  19931. each$3(format.classes, value => {
  19932. const newValue = removeVars(value);
  19933. if (!dom.hasClass(previewElm, newValue)) {
  19934. dom.addClass(previewElm, newValue);
  19935. }
  19936. });
  19937. editor.dispatch('PreviewFormats');
  19938. dom.setStyles(previewFrag, {
  19939. position: 'absolute',
  19940. left: -65535
  19941. });
  19942. editor.getBody().appendChild(previewFrag);
  19943. const rawParentFontSize = getComputedStyle('fontSize');
  19944. const parentFontSize = /px$/.test(rawParentFontSize) ? parseInt(rawParentFontSize, 10) : 0;
  19945. each$3(previewStyles.split(' '), name => {
  19946. let value = getComputedStyle(name, previewElm);
  19947. if (name === 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
  19948. value = getComputedStyle(name);
  19949. if (rgbaToHexString(value).toLowerCase() === '#ffffff') {
  19950. return;
  19951. }
  19952. }
  19953. if (name === 'color') {
  19954. if (rgbaToHexString(value).toLowerCase() === '#000000') {
  19955. return;
  19956. }
  19957. }
  19958. if (name === 'font-size') {
  19959. if (/em|%$/.test(value)) {
  19960. if (parentFontSize === 0) {
  19961. return;
  19962. }
  19963. const numValue = parseFloat(value) / (/%$/.test(value) ? 100 : 1);
  19964. value = numValue * parentFontSize + 'px';
  19965. }
  19966. }
  19967. if (name === 'border' && value) {
  19968. previewCss += 'padding:0 2px;';
  19969. }
  19970. previewCss += name + ':' + value + ';';
  19971. });
  19972. editor.dispatch('AfterPreviewFormats');
  19973. dom.remove(previewFrag);
  19974. return previewCss;
  19975. };
  19976. const setup$r = editor => {
  19977. editor.addShortcut('meta+b', '', 'Bold');
  19978. editor.addShortcut('meta+i', '', 'Italic');
  19979. editor.addShortcut('meta+u', '', 'Underline');
  19980. for (let i = 1; i <= 6; i++) {
  19981. editor.addShortcut('access+' + i, '', [
  19982. 'FormatBlock',
  19983. false,
  19984. 'h' + i
  19985. ]);
  19986. }
  19987. editor.addShortcut('access+7', '', [
  19988. 'FormatBlock',
  19989. false,
  19990. 'p'
  19991. ]);
  19992. editor.addShortcut('access+8', '', [
  19993. 'FormatBlock',
  19994. false,
  19995. 'div'
  19996. ]);
  19997. editor.addShortcut('access+9', '', [
  19998. 'FormatBlock',
  19999. false,
  20000. 'address'
  20001. ]);
  20002. };
  20003. const Formatter = editor => {
  20004. const formats = FormatRegistry(editor);
  20005. const formatChangeState = Cell({});
  20006. setup$r(editor);
  20007. setup$u(editor);
  20008. if (!isRtc(editor)) {
  20009. setup$t(formatChangeState, editor);
  20010. }
  20011. return {
  20012. get: formats.get,
  20013. has: formats.has,
  20014. register: formats.register,
  20015. unregister: formats.unregister,
  20016. apply: (name, vars, node) => {
  20017. applyFormat(editor, name, vars, node);
  20018. },
  20019. remove: (name, vars, node, similar) => {
  20020. removeFormat(editor, name, vars, node, similar);
  20021. },
  20022. toggle: (name, vars, node) => {
  20023. toggleFormat(editor, name, vars, node);
  20024. },
  20025. match: (name, vars, node, similar) => matchFormat(editor, name, vars, node, similar),
  20026. closest: names => closestFormat(editor, names),
  20027. matchAll: (names, vars) => matchAllFormats(editor, names, vars),
  20028. matchNode: (node, name, vars, similar) => matchNodeFormat(editor, node, name, vars, similar),
  20029. canApply: name => canApplyFormat(editor, name),
  20030. formatChanged: (formats, callback, similar, vars) => formatChanged(editor, formatChangeState, formats, callback, similar, vars),
  20031. getCssText: curry(getCssText, editor)
  20032. };
  20033. };
  20034. const shouldIgnoreCommand = cmd => {
  20035. switch (cmd.toLowerCase()) {
  20036. case 'undo':
  20037. case 'redo':
  20038. case 'mcefocus':
  20039. return true;
  20040. default:
  20041. return false;
  20042. }
  20043. };
  20044. const registerEvents = (editor, undoManager, locks) => {
  20045. const isFirstTypedCharacter = Cell(false);
  20046. const addNonTypingUndoLevel = e => {
  20047. setTyping(undoManager, false, locks);
  20048. undoManager.add({}, e);
  20049. };
  20050. editor.on('init', () => {
  20051. undoManager.add();
  20052. });
  20053. editor.on('BeforeExecCommand', e => {
  20054. const cmd = e.command;
  20055. if (!shouldIgnoreCommand(cmd)) {
  20056. endTyping(undoManager, locks);
  20057. undoManager.beforeChange();
  20058. }
  20059. });
  20060. editor.on('ExecCommand', e => {
  20061. const cmd = e.command;
  20062. if (!shouldIgnoreCommand(cmd)) {
  20063. addNonTypingUndoLevel(e);
  20064. }
  20065. });
  20066. editor.on('ObjectResizeStart cut', () => {
  20067. undoManager.beforeChange();
  20068. });
  20069. editor.on('SaveContent ObjectResized blur', addNonTypingUndoLevel);
  20070. editor.on('dragend', addNonTypingUndoLevel);
  20071. editor.on('keyup', e => {
  20072. const keyCode = e.keyCode;
  20073. if (e.isDefaultPrevented()) {
  20074. return;
  20075. }
  20076. if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45 || e.ctrlKey) {
  20077. addNonTypingUndoLevel();
  20078. editor.nodeChanged();
  20079. }
  20080. if (keyCode === 46 || keyCode === 8) {
  20081. editor.nodeChanged();
  20082. }
  20083. if (isFirstTypedCharacter.get() && undoManager.typing && !isEq$1(createFromEditor(editor), undoManager.data[0])) {
  20084. if (!editor.isDirty()) {
  20085. editor.setDirty(true);
  20086. }
  20087. editor.dispatch('TypingUndo');
  20088. isFirstTypedCharacter.set(false);
  20089. editor.nodeChanged();
  20090. }
  20091. });
  20092. editor.on('keydown', e => {
  20093. const keyCode = e.keyCode;
  20094. if (e.isDefaultPrevented()) {
  20095. return;
  20096. }
  20097. if (keyCode >= 33 && keyCode <= 36 || keyCode >= 37 && keyCode <= 40 || keyCode === 45) {
  20098. if (undoManager.typing) {
  20099. addNonTypingUndoLevel(e);
  20100. }
  20101. return;
  20102. }
  20103. const modKey = e.ctrlKey && !e.altKey || e.metaKey;
  20104. if ((keyCode < 16 || keyCode > 20) && keyCode !== 224 && keyCode !== 91 && !undoManager.typing && !modKey) {
  20105. undoManager.beforeChange();
  20106. setTyping(undoManager, true, locks);
  20107. undoManager.add({}, e);
  20108. isFirstTypedCharacter.set(true);
  20109. }
  20110. });
  20111. editor.on('mousedown', e => {
  20112. if (undoManager.typing) {
  20113. addNonTypingUndoLevel(e);
  20114. }
  20115. });
  20116. const isInsertReplacementText = event => event.inputType === 'insertReplacementText';
  20117. const isInsertTextDataNull = event => event.inputType === 'insertText' && event.data === null;
  20118. const isInsertFromPasteOrDrop = event => event.inputType === 'insertFromPaste' || event.inputType === 'insertFromDrop';
  20119. editor.on('input', e => {
  20120. if (e.inputType && (isInsertReplacementText(e) || isInsertTextDataNull(e) || isInsertFromPasteOrDrop(e))) {
  20121. addNonTypingUndoLevel(e);
  20122. }
  20123. });
  20124. editor.on('AddUndo Undo Redo ClearUndos', e => {
  20125. if (!e.isDefaultPrevented()) {
  20126. editor.nodeChanged();
  20127. }
  20128. });
  20129. };
  20130. const addKeyboardShortcuts = editor => {
  20131. editor.addShortcut('meta+z', '', 'Undo');
  20132. editor.addShortcut('meta+y,meta+shift+z', '', 'Redo');
  20133. };
  20134. const UndoManager = editor => {
  20135. const beforeBookmark = value$2();
  20136. const locks = Cell(0);
  20137. const index = Cell(0);
  20138. const undoManager = {
  20139. data: [],
  20140. typing: false,
  20141. beforeChange: () => {
  20142. beforeChange(editor, locks, beforeBookmark);
  20143. },
  20144. add: (level, event) => {
  20145. return addUndoLevel(editor, undoManager, index, locks, beforeBookmark, level, event);
  20146. },
  20147. dispatchChange: () => {
  20148. editor.setDirty(true);
  20149. const level = createFromEditor(editor);
  20150. level.bookmark = getUndoBookmark(editor.selection);
  20151. editor.dispatch('change', {
  20152. level,
  20153. lastLevel: get$b(undoManager.data, index.get()).getOrUndefined()
  20154. });
  20155. },
  20156. undo: () => {
  20157. return undo(editor, undoManager, locks, index);
  20158. },
  20159. redo: () => {
  20160. return redo(editor, index, undoManager.data);
  20161. },
  20162. clear: () => {
  20163. clear(editor, undoManager, index);
  20164. },
  20165. reset: () => {
  20166. reset(editor, undoManager);
  20167. },
  20168. hasUndo: () => {
  20169. return hasUndo(editor, undoManager, index);
  20170. },
  20171. hasRedo: () => {
  20172. return hasRedo(editor, undoManager, index);
  20173. },
  20174. transact: callback => {
  20175. return transact(editor, undoManager, locks, callback);
  20176. },
  20177. ignore: callback => {
  20178. ignore(editor, locks, callback);
  20179. },
  20180. extra: (callback1, callback2) => {
  20181. extra(editor, undoManager, index, callback1, callback2);
  20182. }
  20183. };
  20184. if (!isRtc(editor)) {
  20185. registerEvents(editor, undoManager, locks);
  20186. }
  20187. addKeyboardShortcuts(editor);
  20188. return undoManager;
  20189. };
  20190. const nonTypingKeycodes = [
  20191. 9,
  20192. 27,
  20193. VK.HOME,
  20194. VK.END,
  20195. 19,
  20196. 20,
  20197. 44,
  20198. 144,
  20199. 145,
  20200. 33,
  20201. 34,
  20202. 45,
  20203. 16,
  20204. 17,
  20205. 18,
  20206. 91,
  20207. 92,
  20208. 93,
  20209. VK.DOWN,
  20210. VK.UP,
  20211. VK.LEFT,
  20212. VK.RIGHT
  20213. ].concat(Env.browser.isFirefox() ? [224] : []);
  20214. const placeholderAttr = 'data-mce-placeholder';
  20215. const isKeyboardEvent = e => e.type === 'keydown' || e.type === 'keyup';
  20216. const isDeleteEvent = e => {
  20217. const keyCode = e.keyCode;
  20218. return keyCode === VK.BACKSPACE || keyCode === VK.DELETE;
  20219. };
  20220. const isNonTypingKeyboardEvent = e => {
  20221. if (isKeyboardEvent(e)) {
  20222. const keyCode = e.keyCode;
  20223. return !isDeleteEvent(e) && (VK.metaKeyPressed(e) || e.altKey || keyCode >= 112 && keyCode <= 123 || contains$2(nonTypingKeycodes, keyCode));
  20224. } else {
  20225. return false;
  20226. }
  20227. };
  20228. const isTypingKeyboardEvent = e => isKeyboardEvent(e) && !(isDeleteEvent(e) || e.type === 'keyup' && e.keyCode === 229);
  20229. const isVisuallyEmpty = (dom, rootElm, forcedRootBlock) => {
  20230. if (isEmpty$2(SugarElement.fromDom(rootElm), false)) {
  20231. const firstElement = rootElm.firstElementChild;
  20232. if (!firstElement) {
  20233. return true;
  20234. } else if (dom.getStyle(rootElm.firstElementChild, 'padding-left') || dom.getStyle(rootElm.firstElementChild, 'padding-right')) {
  20235. return false;
  20236. } else {
  20237. return forcedRootBlock === firstElement.nodeName.toLowerCase();
  20238. }
  20239. } else {
  20240. return false;
  20241. }
  20242. };
  20243. const setup$q = editor => {
  20244. var _a;
  20245. const dom = editor.dom;
  20246. const rootBlock = getForcedRootBlock(editor);
  20247. const placeholder = (_a = getPlaceholder(editor)) !== null && _a !== void 0 ? _a : '';
  20248. const updatePlaceholder = (e, initial) => {
  20249. if (isNonTypingKeyboardEvent(e)) {
  20250. return;
  20251. }
  20252. const body = editor.getBody();
  20253. const showPlaceholder = isTypingKeyboardEvent(e) ? false : isVisuallyEmpty(dom, body, rootBlock);
  20254. const isPlaceholderShown = dom.getAttrib(body, placeholderAttr) !== '';
  20255. if (isPlaceholderShown !== showPlaceholder || initial) {
  20256. dom.setAttrib(body, placeholderAttr, showPlaceholder ? placeholder : null);
  20257. dom.setAttrib(body, 'aria-placeholder', showPlaceholder ? placeholder : null);
  20258. firePlaceholderToggle(editor, showPlaceholder);
  20259. editor.on(showPlaceholder ? 'keydown' : 'keyup', updatePlaceholder);
  20260. editor.off(showPlaceholder ? 'keyup' : 'keydown', updatePlaceholder);
  20261. }
  20262. };
  20263. if (isNotEmpty(placeholder)) {
  20264. editor.on('init', e => {
  20265. updatePlaceholder(e, true);
  20266. editor.on('change SetContent ExecCommand', updatePlaceholder);
  20267. editor.on('paste', e => Delay.setEditorTimeout(editor, () => updatePlaceholder(e)));
  20268. });
  20269. }
  20270. };
  20271. const blockPosition = (block, position) => ({
  20272. block,
  20273. position
  20274. });
  20275. const blockBoundary = (from, to) => ({
  20276. from,
  20277. to
  20278. });
  20279. const getBlockPosition = (rootNode, pos) => {
  20280. const rootElm = SugarElement.fromDom(rootNode);
  20281. const containerElm = SugarElement.fromDom(pos.container());
  20282. return getParentBlock$2(rootElm, containerElm).map(block => blockPosition(block, pos));
  20283. };
  20284. const isDifferentBlocks = blockBoundary => !eq(blockBoundary.from.block, blockBoundary.to.block);
  20285. const getClosestHost = (root, scope) => {
  20286. const isRoot = node => eq(node, root);
  20287. const isHost = node => isTableCell$2(node) || isContentEditableTrue$3(node.dom);
  20288. return closest$4(scope, isHost, isRoot).filter(isElement$7).getOr(root);
  20289. };
  20290. const hasSameHost = (rootNode, blockBoundary) => {
  20291. const root = SugarElement.fromDom(rootNode);
  20292. return eq(getClosestHost(root, blockBoundary.from.block), getClosestHost(root, blockBoundary.to.block));
  20293. };
  20294. const isEditable$2 = blockBoundary => isContentEditableFalse$a(blockBoundary.from.block.dom) === false && isContentEditableFalse$a(blockBoundary.to.block.dom) === false;
  20295. const hasValidBlocks = blockBoundary => {
  20296. const isValidBlock = block => isTextBlock$2(block) || hasBlockAttr(block.dom);
  20297. return isValidBlock(blockBoundary.from.block) && isValidBlock(blockBoundary.to.block);
  20298. };
  20299. const skipLastBr = (rootNode, forward, blockPosition) => {
  20300. if (isBr$6(blockPosition.position.getNode()) && !isEmpty$2(blockPosition.block)) {
  20301. return positionIn(false, blockPosition.block.dom).bind(lastPositionInBlock => {
  20302. if (lastPositionInBlock.isEqual(blockPosition.position)) {
  20303. return fromPosition(forward, rootNode, lastPositionInBlock).bind(to => getBlockPosition(rootNode, to));
  20304. } else {
  20305. return Optional.some(blockPosition);
  20306. }
  20307. }).getOr(blockPosition);
  20308. } else {
  20309. return blockPosition;
  20310. }
  20311. };
  20312. const readFromRange = (rootNode, forward, rng) => {
  20313. const fromBlockPos = getBlockPosition(rootNode, CaretPosition.fromRangeStart(rng));
  20314. const toBlockPos = fromBlockPos.bind(blockPos => fromPosition(forward, rootNode, blockPos.position).bind(to => getBlockPosition(rootNode, to).map(blockPos => skipLastBr(rootNode, forward, blockPos))));
  20315. return lift2(fromBlockPos, toBlockPos, blockBoundary).filter(blockBoundary => isDifferentBlocks(blockBoundary) && hasSameHost(rootNode, blockBoundary) && isEditable$2(blockBoundary) && hasValidBlocks(blockBoundary));
  20316. };
  20317. const read$1 = (rootNode, forward, rng) => rng.collapsed ? readFromRange(rootNode, forward, rng) : Optional.none();
  20318. const getChildrenUntilBlockBoundary = block => {
  20319. const children = children$1(block);
  20320. return findIndex$2(children, isBlock$2).fold(constant(children), index => children.slice(0, index));
  20321. };
  20322. const extractChildren = block => {
  20323. const children = getChildrenUntilBlockBoundary(block);
  20324. each$e(children, remove$6);
  20325. return children;
  20326. };
  20327. const removeEmptyRoot = (rootNode, block) => {
  20328. const parents = parentsAndSelf(block, rootNode);
  20329. return find$2(parents.reverse(), element => isEmpty$2(element)).each(remove$6);
  20330. };
  20331. const isEmptyBefore = el => filter$5(prevSiblings(el), el => !isEmpty$2(el)).length === 0;
  20332. const nestedBlockMerge = (rootNode, fromBlock, toBlock, insertionPoint) => {
  20333. if (isEmpty$2(toBlock)) {
  20334. fillWithPaddingBr(toBlock);
  20335. return firstPositionIn(toBlock.dom);
  20336. }
  20337. if (isEmptyBefore(insertionPoint) && isEmpty$2(fromBlock)) {
  20338. before$3(insertionPoint, SugarElement.fromTag('br'));
  20339. }
  20340. const position = prevPosition(toBlock.dom, CaretPosition.before(insertionPoint.dom));
  20341. each$e(extractChildren(fromBlock), child => {
  20342. before$3(insertionPoint, child);
  20343. });
  20344. removeEmptyRoot(rootNode, fromBlock);
  20345. return position;
  20346. };
  20347. const sidelongBlockMerge = (rootNode, fromBlock, toBlock) => {
  20348. if (isEmpty$2(toBlock)) {
  20349. remove$6(toBlock);
  20350. if (isEmpty$2(fromBlock)) {
  20351. fillWithPaddingBr(fromBlock);
  20352. }
  20353. return firstPositionIn(fromBlock.dom);
  20354. }
  20355. const position = lastPositionIn(toBlock.dom);
  20356. each$e(extractChildren(fromBlock), child => {
  20357. append$1(toBlock, child);
  20358. });
  20359. removeEmptyRoot(rootNode, fromBlock);
  20360. return position;
  20361. };
  20362. const findInsertionPoint = (toBlock, block) => {
  20363. const parentsAndSelf$1 = parentsAndSelf(block, toBlock);
  20364. return Optional.from(parentsAndSelf$1[parentsAndSelf$1.length - 1]);
  20365. };
  20366. const getInsertionPoint = (fromBlock, toBlock) => contains(toBlock, fromBlock) ? findInsertionPoint(toBlock, fromBlock) : Optional.none();
  20367. const trimBr = (first, block) => {
  20368. positionIn(first, block.dom).bind(position => Optional.from(position.getNode())).map(SugarElement.fromDom).filter(isBr$5).each(remove$6);
  20369. };
  20370. const mergeBlockInto = (rootNode, fromBlock, toBlock) => {
  20371. trimBr(true, fromBlock);
  20372. trimBr(false, toBlock);
  20373. return getInsertionPoint(fromBlock, toBlock).fold(curry(sidelongBlockMerge, rootNode, fromBlock, toBlock), curry(nestedBlockMerge, rootNode, fromBlock, toBlock));
  20374. };
  20375. const mergeBlocks = (rootNode, forward, block1, block2) => forward ? mergeBlockInto(rootNode, block2, block1) : mergeBlockInto(rootNode, block1, block2);
  20376. const backspaceDelete$8 = (editor, forward) => {
  20377. const rootNode = SugarElement.fromDom(editor.getBody());
  20378. const position = read$1(rootNode.dom, forward, editor.selection.getRng()).map(blockBoundary => () => {
  20379. mergeBlocks(rootNode, forward, blockBoundary.from.block, blockBoundary.to.block).each(pos => {
  20380. editor.selection.setRng(pos.toRange());
  20381. });
  20382. });
  20383. return position;
  20384. };
  20385. const deleteRangeMergeBlocks = (rootNode, selection) => {
  20386. const rng = selection.getRng();
  20387. return lift2(getParentBlock$2(rootNode, SugarElement.fromDom(rng.startContainer)), getParentBlock$2(rootNode, SugarElement.fromDom(rng.endContainer)), (block1, block2) => {
  20388. if (!eq(block1, block2)) {
  20389. return Optional.some(() => {
  20390. rng.deleteContents();
  20391. mergeBlocks(rootNode, true, block1, block2).each(pos => {
  20392. selection.setRng(pos.toRange());
  20393. });
  20394. });
  20395. } else {
  20396. return Optional.none();
  20397. }
  20398. }).getOr(Optional.none());
  20399. };
  20400. const isRawNodeInTable = (root, rawNode) => {
  20401. const node = SugarElement.fromDom(rawNode);
  20402. const isRoot = curry(eq, root);
  20403. return ancestor$3(node, isTableCell$2, isRoot).isSome();
  20404. };
  20405. const isSelectionInTable = (root, rng) => isRawNodeInTable(root, rng.startContainer) || isRawNodeInTable(root, rng.endContainer);
  20406. const isEverythingSelected = (root, rng) => {
  20407. const noPrevious = prevPosition(root.dom, CaretPosition.fromRangeStart(rng)).isNone();
  20408. const noNext = nextPosition(root.dom, CaretPosition.fromRangeEnd(rng)).isNone();
  20409. return !isSelectionInTable(root, rng) && noPrevious && noNext;
  20410. };
  20411. const emptyEditor = editor => {
  20412. return Optional.some(() => {
  20413. editor.setContent('');
  20414. editor.selection.setCursorLocation();
  20415. });
  20416. };
  20417. const deleteRange$1 = editor => {
  20418. const rootNode = SugarElement.fromDom(editor.getBody());
  20419. const rng = editor.selection.getRng();
  20420. return isEverythingSelected(rootNode, rng) ? emptyEditor(editor) : deleteRangeMergeBlocks(rootNode, editor.selection);
  20421. };
  20422. const backspaceDelete$7 = (editor, _forward) => editor.selection.isCollapsed() ? Optional.none() : deleteRange$1(editor);
  20423. const showCaret = (direction, editor, node, before, scrollIntoView) => Optional.from(editor._selectionOverrides.showCaret(direction, node, before, scrollIntoView));
  20424. const getNodeRange = node => {
  20425. const rng = node.ownerDocument.createRange();
  20426. rng.selectNode(node);
  20427. return rng;
  20428. };
  20429. const selectNode = (editor, node) => {
  20430. const e = editor.dispatch('BeforeObjectSelected', { target: node });
  20431. if (e.isDefaultPrevented()) {
  20432. return Optional.none();
  20433. }
  20434. return Optional.some(getNodeRange(node));
  20435. };
  20436. const renderCaretAtRange = (editor, range, scrollIntoView) => {
  20437. const normalizedRange = normalizeRange(1, editor.getBody(), range);
  20438. const caretPosition = CaretPosition.fromRangeStart(normalizedRange);
  20439. const caretPositionNode = caretPosition.getNode();
  20440. if (isInlineFakeCaretTarget(caretPositionNode)) {
  20441. return showCaret(1, editor, caretPositionNode, !caretPosition.isAtEnd(), false);
  20442. }
  20443. const caretPositionBeforeNode = caretPosition.getNode(true);
  20444. if (isInlineFakeCaretTarget(caretPositionBeforeNode)) {
  20445. return showCaret(1, editor, caretPositionBeforeNode, false, false);
  20446. }
  20447. const ceRoot = getContentEditableRoot$1(editor.dom.getRoot(), caretPosition.getNode());
  20448. if (isInlineFakeCaretTarget(ceRoot)) {
  20449. return showCaret(1, editor, ceRoot, false, scrollIntoView);
  20450. }
  20451. return Optional.none();
  20452. };
  20453. const renderRangeCaret = (editor, range, scrollIntoView) => range.collapsed ? renderCaretAtRange(editor, range, scrollIntoView).getOr(range) : range;
  20454. const isBeforeBoundary = pos => isBeforeContentEditableFalse(pos) || isBeforeMedia(pos);
  20455. const isAfterBoundary = pos => isAfterContentEditableFalse(pos) || isAfterMedia(pos);
  20456. const trimEmptyTextNode = (dom, node) => {
  20457. if (isText$a(node) && node.data.length === 0) {
  20458. dom.remove(node);
  20459. }
  20460. };
  20461. const deleteContentAndShowCaret = (editor, range, node, direction, forward, peekCaretPosition) => {
  20462. showCaret(direction, editor, peekCaretPosition.getNode(!forward), forward, true).each(caretRange => {
  20463. if (range.collapsed) {
  20464. const deleteRange = range.cloneRange();
  20465. if (forward) {
  20466. deleteRange.setEnd(caretRange.startContainer, caretRange.startOffset);
  20467. } else {
  20468. deleteRange.setStart(caretRange.endContainer, caretRange.endOffset);
  20469. }
  20470. deleteRange.deleteContents();
  20471. } else {
  20472. range.deleteContents();
  20473. }
  20474. editor.selection.setRng(caretRange);
  20475. });
  20476. trimEmptyTextNode(editor.dom, node);
  20477. };
  20478. const deleteBoundaryText = (editor, forward) => {
  20479. const range = editor.selection.getRng();
  20480. if (!isText$a(range.commonAncestorContainer)) {
  20481. return Optional.none();
  20482. }
  20483. const direction = forward ? HDirection.Forwards : HDirection.Backwards;
  20484. const caretWalker = CaretWalker(editor.getBody());
  20485. const getNextPosFn = curry(getVisualCaretPosition, forward ? caretWalker.next : caretWalker.prev);
  20486. const isBeforeFn = forward ? isBeforeBoundary : isAfterBoundary;
  20487. const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
  20488. const nextCaretPosition = getNextPosFn(caretPosition);
  20489. const normalizedNextCaretPosition = nextCaretPosition ? normalizePosition(forward, nextCaretPosition) : nextCaretPosition;
  20490. if (!normalizedNextCaretPosition || !isMoveInsideSameBlock(caretPosition, normalizedNextCaretPosition)) {
  20491. return Optional.none();
  20492. } else if (isBeforeFn(normalizedNextCaretPosition)) {
  20493. return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, normalizedNextCaretPosition));
  20494. }
  20495. const peekCaretPosition = getNextPosFn(normalizedNextCaretPosition);
  20496. if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
  20497. if (isMoveInsideSameBlock(normalizedNextCaretPosition, peekCaretPosition)) {
  20498. return Optional.some(() => deleteContentAndShowCaret(editor, range, caretPosition.getNode(), direction, forward, peekCaretPosition));
  20499. }
  20500. }
  20501. return Optional.none();
  20502. };
  20503. const backspaceDelete$6 = (editor, forward) => deleteBoundaryText(editor, forward);
  20504. const getEdgeCefPosition = (editor, atStart) => {
  20505. const root = editor.getBody();
  20506. return atStart ? firstPositionIn(root).filter(isBeforeContentEditableFalse) : lastPositionIn(root).filter(isAfterContentEditableFalse);
  20507. };
  20508. const isCefAtEdgeSelected = editor => {
  20509. const rng = editor.selection.getRng();
  20510. return !rng.collapsed && (getEdgeCefPosition(editor, true).exists(pos => pos.isEqual(CaretPosition.fromRangeStart(rng))) || getEdgeCefPosition(editor, false).exists(pos => pos.isEqual(CaretPosition.fromRangeEnd(rng))));
  20511. };
  20512. const isCompoundElement = node => isNonNullable(node) && (isTableCell$2(SugarElement.fromDom(node)) || isListItem$1(SugarElement.fromDom(node)));
  20513. const DeleteAction = Adt.generate([
  20514. { remove: ['element'] },
  20515. { moveToElement: ['element'] },
  20516. { moveToPosition: ['position'] }
  20517. ]);
  20518. const isAtContentEditableBlockCaret = (forward, from) => {
  20519. const elm = from.getNode(!forward);
  20520. const caretLocation = forward ? 'after' : 'before';
  20521. return isElement$6(elm) && elm.getAttribute('data-mce-caret') === caretLocation;
  20522. };
  20523. const isDeleteFromCefDifferentBlocks = (root, forward, from, to) => {
  20524. const inSameBlock = elm => isInline$1(SugarElement.fromDom(elm)) && !isInSameBlock(from, to, root);
  20525. return getRelativeCefElm(!forward, from).fold(() => getRelativeCefElm(forward, to).fold(never, inSameBlock), inSameBlock);
  20526. };
  20527. const deleteEmptyBlockOrMoveToCef = (root, forward, from, to) => {
  20528. const toCefElm = to.getNode(!forward);
  20529. return getParentBlock$2(SugarElement.fromDom(root), SugarElement.fromDom(from.getNode())).map(blockElm => isEmpty$2(blockElm) ? DeleteAction.remove(blockElm.dom) : DeleteAction.moveToElement(toCefElm)).orThunk(() => Optional.some(DeleteAction.moveToElement(toCefElm)));
  20530. };
  20531. const findCefPosition = (root, forward, from) => fromPosition(forward, root, from).bind(to => {
  20532. if (isCompoundElement(to.getNode())) {
  20533. return Optional.none();
  20534. } else if (isDeleteFromCefDifferentBlocks(root, forward, from, to)) {
  20535. return Optional.none();
  20536. } else if (forward && isContentEditableFalse$a(to.getNode())) {
  20537. return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
  20538. } else if (!forward && isContentEditableFalse$a(to.getNode(true))) {
  20539. return deleteEmptyBlockOrMoveToCef(root, forward, from, to);
  20540. } else if (forward && isAfterContentEditableFalse(from)) {
  20541. return Optional.some(DeleteAction.moveToPosition(to));
  20542. } else if (!forward && isBeforeContentEditableFalse(from)) {
  20543. return Optional.some(DeleteAction.moveToPosition(to));
  20544. } else {
  20545. return Optional.none();
  20546. }
  20547. });
  20548. const getContentEditableBlockAction = (forward, elm) => {
  20549. if (isNullable(elm)) {
  20550. return Optional.none();
  20551. } else if (forward && isContentEditableFalse$a(elm.nextSibling)) {
  20552. return Optional.some(DeleteAction.moveToElement(elm.nextSibling));
  20553. } else if (!forward && isContentEditableFalse$a(elm.previousSibling)) {
  20554. return Optional.some(DeleteAction.moveToElement(elm.previousSibling));
  20555. } else {
  20556. return Optional.none();
  20557. }
  20558. };
  20559. const skipMoveToActionFromInlineCefToContent = (root, from, deleteAction) => deleteAction.fold(elm => Optional.some(DeleteAction.remove(elm)), elm => Optional.some(DeleteAction.moveToElement(elm)), to => {
  20560. if (isInSameBlock(from, to, root)) {
  20561. return Optional.none();
  20562. } else {
  20563. return Optional.some(DeleteAction.moveToPosition(to));
  20564. }
  20565. });
  20566. const getContentEditableAction = (root, forward, from) => {
  20567. if (isAtContentEditableBlockCaret(forward, from)) {
  20568. return getContentEditableBlockAction(forward, from.getNode(!forward)).orThunk(() => findCefPosition(root, forward, from));
  20569. } else {
  20570. return findCefPosition(root, forward, from).bind(deleteAction => skipMoveToActionFromInlineCefToContent(root, from, deleteAction));
  20571. }
  20572. };
  20573. const read = (root, forward, rng) => {
  20574. const normalizedRange = normalizeRange(forward ? 1 : -1, root, rng);
  20575. const from = CaretPosition.fromRangeStart(normalizedRange);
  20576. const rootElement = SugarElement.fromDom(root);
  20577. if (!forward && isAfterContentEditableFalse(from)) {
  20578. return Optional.some(DeleteAction.remove(from.getNode(true)));
  20579. } else if (forward && isBeforeContentEditableFalse(from)) {
  20580. return Optional.some(DeleteAction.remove(from.getNode()));
  20581. } else if (!forward && isBeforeContentEditableFalse(from) && isAfterBr(rootElement, from)) {
  20582. return findPreviousBr(rootElement, from).map(br => DeleteAction.remove(br.getNode()));
  20583. } else if (forward && isAfterContentEditableFalse(from) && isBeforeBr$1(rootElement, from)) {
  20584. return findNextBr(rootElement, from).map(br => DeleteAction.remove(br.getNode()));
  20585. } else {
  20586. return getContentEditableAction(root, forward, from);
  20587. }
  20588. };
  20589. const deleteElement$1 = (editor, forward) => element => {
  20590. editor._selectionOverrides.hideFakeCaret();
  20591. deleteElement$2(editor, forward, SugarElement.fromDom(element));
  20592. return true;
  20593. };
  20594. const moveToElement = (editor, forward) => element => {
  20595. const pos = forward ? CaretPosition.before(element) : CaretPosition.after(element);
  20596. editor.selection.setRng(pos.toRange());
  20597. return true;
  20598. };
  20599. const moveToPosition = editor => pos => {
  20600. editor.selection.setRng(pos.toRange());
  20601. return true;
  20602. };
  20603. const getAncestorCe = (editor, node) => Optional.from(getContentEditableRoot$1(editor.getBody(), node));
  20604. const backspaceDeleteCaret = (editor, forward) => {
  20605. const selectedNode = editor.selection.getNode();
  20606. return getAncestorCe(editor, selectedNode).filter(isContentEditableFalse$a).fold(() => read(editor.getBody(), forward, editor.selection.getRng()).map(deleteAction => () => deleteAction.fold(deleteElement$1(editor, forward), moveToElement(editor, forward), moveToPosition(editor))), () => Optional.some(noop));
  20607. };
  20608. const deleteOffscreenSelection = rootElement => {
  20609. each$e(descendants(rootElement, '.mce-offscreen-selection'), remove$6);
  20610. };
  20611. const backspaceDeleteRange = (editor, forward) => {
  20612. const selectedNode = editor.selection.getNode();
  20613. if (isContentEditableFalse$a(selectedNode) && !isTableCell$3(selectedNode)) {
  20614. const hasCefAncestor = getAncestorCe(editor, selectedNode.parentNode).filter(isContentEditableFalse$a);
  20615. return hasCefAncestor.fold(() => Optional.some(() => {
  20616. deleteOffscreenSelection(SugarElement.fromDom(editor.getBody()));
  20617. deleteElement$2(editor, forward, SugarElement.fromDom(editor.selection.getNode()));
  20618. paddEmptyBody(editor);
  20619. }), () => Optional.some(noop));
  20620. }
  20621. if (isCefAtEdgeSelected(editor)) {
  20622. return Optional.some(() => {
  20623. deleteRangeContents(editor, editor.selection.getRng(), SugarElement.fromDom(editor.getBody()));
  20624. });
  20625. }
  20626. return Optional.none();
  20627. };
  20628. const paddEmptyElement = editor => {
  20629. const dom = editor.dom, selection = editor.selection;
  20630. const ceRoot = getContentEditableRoot$1(editor.getBody(), selection.getNode());
  20631. if (isContentEditableTrue$3(ceRoot) && dom.isBlock(ceRoot) && dom.isEmpty(ceRoot)) {
  20632. const br = dom.create('br', { 'data-mce-bogus': '1' });
  20633. dom.setHTML(ceRoot, '');
  20634. ceRoot.appendChild(br);
  20635. selection.setRng(CaretPosition.before(br).toRange());
  20636. }
  20637. return true;
  20638. };
  20639. const backspaceDelete$5 = (editor, forward) => {
  20640. if (editor.selection.isCollapsed()) {
  20641. return backspaceDeleteCaret(editor, forward);
  20642. } else {
  20643. return backspaceDeleteRange(editor, forward);
  20644. }
  20645. };
  20646. const deleteCaret$2 = (editor, forward) => {
  20647. const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
  20648. return fromPosition(forward, editor.getBody(), fromPos).filter(pos => forward ? isBeforeImageBlock(pos) : isAfterImageBlock(pos)).bind(pos => getChildNodeAtRelativeOffset(forward ? 0 : -1, pos)).map(elm => () => editor.selection.select(elm));
  20649. };
  20650. const backspaceDelete$4 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$2(editor, forward) : Optional.none();
  20651. const isText$2 = isText$a;
  20652. const startsWithCaretContainer = node => isText$2(node) && node.data[0] === ZWSP$1;
  20653. const endsWithCaretContainer = node => isText$2(node) && node.data[node.data.length - 1] === ZWSP$1;
  20654. const createZwsp = node => {
  20655. var _a;
  20656. const doc = (_a = node.ownerDocument) !== null && _a !== void 0 ? _a : document;
  20657. return doc.createTextNode(ZWSP$1);
  20658. };
  20659. const insertBefore = node => {
  20660. var _a;
  20661. if (isText$2(node.previousSibling)) {
  20662. if (endsWithCaretContainer(node.previousSibling)) {
  20663. return node.previousSibling;
  20664. } else {
  20665. node.previousSibling.appendData(ZWSP$1);
  20666. return node.previousSibling;
  20667. }
  20668. } else if (isText$2(node)) {
  20669. if (startsWithCaretContainer(node)) {
  20670. return node;
  20671. } else {
  20672. node.insertData(0, ZWSP$1);
  20673. return node;
  20674. }
  20675. } else {
  20676. const newNode = createZwsp(node);
  20677. (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node);
  20678. return newNode;
  20679. }
  20680. };
  20681. const insertAfter = node => {
  20682. var _a, _b;
  20683. if (isText$2(node.nextSibling)) {
  20684. if (startsWithCaretContainer(node.nextSibling)) {
  20685. return node.nextSibling;
  20686. } else {
  20687. node.nextSibling.insertData(0, ZWSP$1);
  20688. return node.nextSibling;
  20689. }
  20690. } else if (isText$2(node)) {
  20691. if (endsWithCaretContainer(node)) {
  20692. return node;
  20693. } else {
  20694. node.appendData(ZWSP$1);
  20695. return node;
  20696. }
  20697. } else {
  20698. const newNode = createZwsp(node);
  20699. if (node.nextSibling) {
  20700. (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(newNode, node.nextSibling);
  20701. } else {
  20702. (_b = node.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(newNode);
  20703. }
  20704. return newNode;
  20705. }
  20706. };
  20707. const insertInline = (before, node) => before ? insertBefore(node) : insertAfter(node);
  20708. const insertInlineBefore = curry(insertInline, true);
  20709. const insertInlineAfter = curry(insertInline, false);
  20710. const insertInlinePos = (pos, before) => {
  20711. if (isText$a(pos.container())) {
  20712. return insertInline(before, pos.container());
  20713. } else {
  20714. return insertInline(before, pos.getNode());
  20715. }
  20716. };
  20717. const isPosCaretContainer = (pos, caret) => {
  20718. const caretNode = caret.get();
  20719. return caretNode && pos.container() === caretNode && isCaretContainerInline(caretNode);
  20720. };
  20721. const renderCaret = (caret, location) => location.fold(element => {
  20722. remove$4(caret.get());
  20723. const text = insertInlineBefore(element);
  20724. caret.set(text);
  20725. return Optional.some(CaretPosition(text, text.length - 1));
  20726. }, element => firstPositionIn(element).map(pos => {
  20727. if (!isPosCaretContainer(pos, caret)) {
  20728. remove$4(caret.get());
  20729. const text = insertInlinePos(pos, true);
  20730. caret.set(text);
  20731. return CaretPosition(text, 1);
  20732. } else {
  20733. const node = caret.get();
  20734. return CaretPosition(node, 1);
  20735. }
  20736. }), element => lastPositionIn(element).map(pos => {
  20737. if (!isPosCaretContainer(pos, caret)) {
  20738. remove$4(caret.get());
  20739. const text = insertInlinePos(pos, false);
  20740. caret.set(text);
  20741. return CaretPosition(text, text.length - 1);
  20742. } else {
  20743. const node = caret.get();
  20744. return CaretPosition(node, node.length - 1);
  20745. }
  20746. }), element => {
  20747. remove$4(caret.get());
  20748. const text = insertInlineAfter(element);
  20749. caret.set(text);
  20750. return Optional.some(CaretPosition(text, 1));
  20751. });
  20752. const evaluateUntil = (fns, args) => {
  20753. for (let i = 0; i < fns.length; i++) {
  20754. const result = fns[i].apply(null, args);
  20755. if (result.isSome()) {
  20756. return result;
  20757. }
  20758. }
  20759. return Optional.none();
  20760. };
  20761. const Location = Adt.generate([
  20762. { before: ['element'] },
  20763. { start: ['element'] },
  20764. { end: ['element'] },
  20765. { after: ['element'] }
  20766. ]);
  20767. const rescope$1 = (rootNode, node) => {
  20768. const parentBlock = getParentBlock$3(node, rootNode);
  20769. return parentBlock ? parentBlock : rootNode;
  20770. };
  20771. const before = (isInlineTarget, rootNode, pos) => {
  20772. const nPos = normalizeForwards(pos);
  20773. const scope = rescope$1(rootNode, nPos.container());
  20774. return findRootInline(isInlineTarget, scope, nPos).fold(() => nextPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.before(inline)), Optional.none);
  20775. };
  20776. const isNotInsideFormatCaretContainer = (rootNode, elm) => getParentCaretContainer(rootNode, elm) === null;
  20777. const findInsideRootInline = (isInlineTarget, rootNode, pos) => findRootInline(isInlineTarget, rootNode, pos).filter(curry(isNotInsideFormatCaretContainer, rootNode));
  20778. const start$1 = (isInlineTarget, rootNode, pos) => {
  20779. const nPos = normalizeBackwards(pos);
  20780. return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
  20781. const prevPos = prevPosition(inline, nPos);
  20782. return prevPos.isNone() ? Optional.some(Location.start(inline)) : Optional.none();
  20783. });
  20784. };
  20785. const end = (isInlineTarget, rootNode, pos) => {
  20786. const nPos = normalizeForwards(pos);
  20787. return findInsideRootInline(isInlineTarget, rootNode, nPos).bind(inline => {
  20788. const nextPos = nextPosition(inline, nPos);
  20789. return nextPos.isNone() ? Optional.some(Location.end(inline)) : Optional.none();
  20790. });
  20791. };
  20792. const after = (isInlineTarget, rootNode, pos) => {
  20793. const nPos = normalizeBackwards(pos);
  20794. const scope = rescope$1(rootNode, nPos.container());
  20795. return findRootInline(isInlineTarget, scope, nPos).fold(() => prevPosition(scope, nPos).bind(curry(findRootInline, isInlineTarget, scope)).map(inline => Location.after(inline)), Optional.none);
  20796. };
  20797. const isValidLocation = location => !isRtl(getElement(location));
  20798. const readLocation = (isInlineTarget, rootNode, pos) => {
  20799. const location = evaluateUntil([
  20800. before,
  20801. start$1,
  20802. end,
  20803. after
  20804. ], [
  20805. isInlineTarget,
  20806. rootNode,
  20807. pos
  20808. ]);
  20809. return location.filter(isValidLocation);
  20810. };
  20811. const getElement = location => location.fold(identity, identity, identity, identity);
  20812. const getName = location => location.fold(constant('before'), constant('start'), constant('end'), constant('after'));
  20813. const outside = location => location.fold(Location.before, Location.before, Location.after, Location.after);
  20814. const inside = location => location.fold(Location.start, Location.start, Location.end, Location.end);
  20815. const isEq = (location1, location2) => getName(location1) === getName(location2) && getElement(location1) === getElement(location2);
  20816. const betweenInlines = (forward, isInlineTarget, rootNode, from, to, location) => lift2(findRootInline(isInlineTarget, rootNode, from), findRootInline(isInlineTarget, rootNode, to), (fromInline, toInline) => {
  20817. if (fromInline !== toInline && hasSameParentBlock(rootNode, fromInline, toInline)) {
  20818. return Location.after(forward ? fromInline : toInline);
  20819. } else {
  20820. return location;
  20821. }
  20822. }).getOr(location);
  20823. const skipNoMovement = (fromLocation, toLocation) => fromLocation.fold(always, fromLocation => !isEq(fromLocation, toLocation));
  20824. const findLocationTraverse = (forward, isInlineTarget, rootNode, fromLocation, pos) => {
  20825. const from = normalizePosition(forward, pos);
  20826. const to = fromPosition(forward, rootNode, from).map(curry(normalizePosition, forward));
  20827. const location = to.fold(() => fromLocation.map(outside), to => readLocation(isInlineTarget, rootNode, to).map(curry(betweenInlines, forward, isInlineTarget, rootNode, from, to)).filter(curry(skipNoMovement, fromLocation)));
  20828. return location.filter(isValidLocation);
  20829. };
  20830. const findLocationSimple = (forward, location) => {
  20831. if (forward) {
  20832. return location.fold(compose(Optional.some, Location.start), Optional.none, compose(Optional.some, Location.after), Optional.none);
  20833. } else {
  20834. return location.fold(Optional.none, compose(Optional.some, Location.before), Optional.none, compose(Optional.some, Location.end));
  20835. }
  20836. };
  20837. const findLocation$1 = (forward, isInlineTarget, rootNode, pos) => {
  20838. const from = normalizePosition(forward, pos);
  20839. const fromLocation = readLocation(isInlineTarget, rootNode, from);
  20840. return readLocation(isInlineTarget, rootNode, from).bind(curry(findLocationSimple, forward)).orThunk(() => findLocationTraverse(forward, isInlineTarget, rootNode, fromLocation, pos));
  20841. };
  20842. const hasSelectionModifyApi = editor => {
  20843. return isFunction(editor.selection.getSel().modify);
  20844. };
  20845. const moveRel = (forward, selection, pos) => {
  20846. const delta = forward ? 1 : -1;
  20847. selection.setRng(CaretPosition(pos.container(), pos.offset() + delta).toRange());
  20848. selection.getSel().modify('move', forward ? 'forward' : 'backward', 'word');
  20849. return true;
  20850. };
  20851. const moveByWord = (forward, editor) => {
  20852. const rng = editor.selection.getRng();
  20853. const pos = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
  20854. if (!hasSelectionModifyApi(editor)) {
  20855. return false;
  20856. } else if (forward && isBeforeInline(pos)) {
  20857. return moveRel(true, editor.selection, pos);
  20858. } else if (!forward && isAfterInline(pos)) {
  20859. return moveRel(false, editor.selection, pos);
  20860. } else {
  20861. return false;
  20862. }
  20863. };
  20864. var BreakType;
  20865. (function (BreakType) {
  20866. BreakType[BreakType['Br'] = 0] = 'Br';
  20867. BreakType[BreakType['Block'] = 1] = 'Block';
  20868. BreakType[BreakType['Wrap'] = 2] = 'Wrap';
  20869. BreakType[BreakType['Eol'] = 3] = 'Eol';
  20870. }(BreakType || (BreakType = {})));
  20871. const flip = (direction, positions) => direction === HDirection.Backwards ? reverse(positions) : positions;
  20872. const walk$1 = (direction, caretWalker, pos) => direction === HDirection.Forwards ? caretWalker.next(pos) : caretWalker.prev(pos);
  20873. const getBreakType = (scope, direction, currentPos, nextPos) => {
  20874. if (isBr$6(nextPos.getNode(direction === HDirection.Forwards))) {
  20875. return BreakType.Br;
  20876. } else if (isInSameBlock(currentPos, nextPos) === false) {
  20877. return BreakType.Block;
  20878. } else {
  20879. return BreakType.Wrap;
  20880. }
  20881. };
  20882. const getPositionsUntil = (predicate, direction, scope, start) => {
  20883. const caretWalker = CaretWalker(scope);
  20884. let currentPos = start;
  20885. const positions = [];
  20886. while (currentPos) {
  20887. const nextPos = walk$1(direction, caretWalker, currentPos);
  20888. if (!nextPos) {
  20889. break;
  20890. }
  20891. if (isBr$6(nextPos.getNode(false))) {
  20892. if (direction === HDirection.Forwards) {
  20893. return {
  20894. positions: flip(direction, positions).concat([nextPos]),
  20895. breakType: BreakType.Br,
  20896. breakAt: Optional.some(nextPos)
  20897. };
  20898. } else {
  20899. return {
  20900. positions: flip(direction, positions),
  20901. breakType: BreakType.Br,
  20902. breakAt: Optional.some(nextPos)
  20903. };
  20904. }
  20905. }
  20906. if (!nextPos.isVisible()) {
  20907. currentPos = nextPos;
  20908. continue;
  20909. }
  20910. if (predicate(currentPos, nextPos)) {
  20911. const breakType = getBreakType(scope, direction, currentPos, nextPos);
  20912. return {
  20913. positions: flip(direction, positions),
  20914. breakType,
  20915. breakAt: Optional.some(nextPos)
  20916. };
  20917. }
  20918. positions.push(nextPos);
  20919. currentPos = nextPos;
  20920. }
  20921. return {
  20922. positions: flip(direction, positions),
  20923. breakType: BreakType.Eol,
  20924. breakAt: Optional.none()
  20925. };
  20926. };
  20927. const getAdjacentLinePositions = (direction, getPositionsUntilBreak, scope, start) => getPositionsUntilBreak(scope, start).breakAt.map(pos => {
  20928. const positions = getPositionsUntilBreak(scope, pos).positions;
  20929. return direction === HDirection.Backwards ? positions.concat(pos) : [pos].concat(positions);
  20930. }).getOr([]);
  20931. const findClosestHorizontalPositionFromPoint = (positions, x) => foldl(positions, (acc, newPos) => acc.fold(() => Optional.some(newPos), lastPos => lift2(head(lastPos.getClientRects()), head(newPos.getClientRects()), (lastRect, newRect) => {
  20932. const lastDist = Math.abs(x - lastRect.left);
  20933. const newDist = Math.abs(x - newRect.left);
  20934. return newDist <= lastDist ? newPos : lastPos;
  20935. }).or(acc)), Optional.none());
  20936. const findClosestHorizontalPosition = (positions, pos) => head(pos.getClientRects()).bind(targetRect => findClosestHorizontalPositionFromPoint(positions, targetRect.left));
  20937. const getPositionsUntilPreviousLine = curry(getPositionsUntil, CaretPosition.isAbove, -1);
  20938. const getPositionsUntilNextLine = curry(getPositionsUntil, CaretPosition.isBelow, 1);
  20939. const getPositionsAbove = curry(getAdjacentLinePositions, -1, getPositionsUntilPreviousLine);
  20940. const getPositionsBelow = curry(getAdjacentLinePositions, 1, getPositionsUntilNextLine);
  20941. const isAtFirstLine = (scope, pos) => getPositionsUntilPreviousLine(scope, pos).breakAt.isNone();
  20942. const isAtLastLine = (scope, pos) => getPositionsUntilNextLine(scope, pos).breakAt.isNone();
  20943. const getFirstLinePositions = scope => firstPositionIn(scope).map(pos => [pos].concat(getPositionsUntilNextLine(scope, pos).positions)).getOr([]);
  20944. const getLastLinePositions = scope => lastPositionIn(scope).map(pos => getPositionsUntilPreviousLine(scope, pos).positions.concat(pos)).getOr([]);
  20945. const getClosestPositionAbove = (scope, pos) => findClosestHorizontalPosition(getPositionsAbove(scope, pos), pos);
  20946. const getClosestPositionBelow = (scope, pos) => findClosestHorizontalPosition(getPositionsBelow(scope, pos), pos);
  20947. const isContentEditableFalse$4 = isContentEditableFalse$a;
  20948. const distanceToRectLeft$1 = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
  20949. const distanceToRectRight$1 = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
  20950. const isNodeClientRect = rect => hasNonNullableKey(rect, 'node');
  20951. const findClosestClientRect = (clientRects, clientX) => reduce(clientRects, (oldClientRect, clientRect) => {
  20952. const oldDistance = Math.min(distanceToRectLeft$1(oldClientRect, clientX), distanceToRectRight$1(oldClientRect, clientX));
  20953. const newDistance = Math.min(distanceToRectLeft$1(clientRect, clientX), distanceToRectRight$1(clientRect, clientX));
  20954. if (newDistance === oldDistance && isNodeClientRect(clientRect) && isContentEditableFalse$4(clientRect.node)) {
  20955. return clientRect;
  20956. }
  20957. if (newDistance < oldDistance) {
  20958. return clientRect;
  20959. }
  20960. return oldClientRect;
  20961. });
  20962. const getNodeClientRects = node => {
  20963. const toArrayWithNode = clientRects => {
  20964. return map$3(clientRects, rect => {
  20965. const clientRect = clone$1(rect);
  20966. clientRect.node = node;
  20967. return clientRect;
  20968. });
  20969. };
  20970. if (isElement$6(node)) {
  20971. return toArrayWithNode(node.getClientRects());
  20972. } else if (isText$a(node)) {
  20973. const rng = node.ownerDocument.createRange();
  20974. rng.setStart(node, 0);
  20975. rng.setEnd(node, node.data.length);
  20976. return toArrayWithNode(rng.getClientRects());
  20977. } else {
  20978. return [];
  20979. }
  20980. };
  20981. const getClientRects = nodes => bind$3(nodes, getNodeClientRects);
  20982. var VDirection;
  20983. (function (VDirection) {
  20984. VDirection[VDirection['Up'] = -1] = 'Up';
  20985. VDirection[VDirection['Down'] = 1] = 'Down';
  20986. }(VDirection || (VDirection = {})));
  20987. const findUntil = (direction, root, predicateFn, node) => {
  20988. let currentNode = node;
  20989. while (currentNode = findNode(currentNode, direction, isEditableCaretCandidate$1, root)) {
  20990. if (predicateFn(currentNode)) {
  20991. return;
  20992. }
  20993. }
  20994. };
  20995. const walkUntil = (direction, isAboveFn, isBeflowFn, root, predicateFn, caretPosition) => {
  20996. let line = 0;
  20997. const result = [];
  20998. const add = node => {
  20999. let clientRects = getClientRects([node]);
  21000. if (direction === -1) {
  21001. clientRects = clientRects.reverse();
  21002. }
  21003. for (let i = 0; i < clientRects.length; i++) {
  21004. const clientRect = clientRects[i];
  21005. if (isBeflowFn(clientRect, targetClientRect)) {
  21006. continue;
  21007. }
  21008. if (result.length > 0 && isAboveFn(clientRect, last$2(result))) {
  21009. line++;
  21010. }
  21011. clientRect.line = line;
  21012. if (predicateFn(clientRect)) {
  21013. return true;
  21014. }
  21015. result.push(clientRect);
  21016. }
  21017. return false;
  21018. };
  21019. const targetClientRect = last$2(caretPosition.getClientRects());
  21020. if (!targetClientRect) {
  21021. return result;
  21022. }
  21023. const node = caretPosition.getNode();
  21024. if (node) {
  21025. add(node);
  21026. findUntil(direction, root, add, node);
  21027. }
  21028. return result;
  21029. };
  21030. const aboveLineNumber = (lineNumber, clientRect) => clientRect.line > lineNumber;
  21031. const isLineNumber = (lineNumber, clientRect) => clientRect.line === lineNumber;
  21032. const upUntil = curry(walkUntil, VDirection.Up, isAbove$1, isBelow$1);
  21033. const downUntil = curry(walkUntil, VDirection.Down, isBelow$1, isAbove$1);
  21034. const getLastClientRect = caretPosition => {
  21035. return last$2(caretPosition.getClientRects());
  21036. };
  21037. const positionsUntil = (direction, root, predicateFn, node) => {
  21038. const caretWalker = CaretWalker(root);
  21039. let walkFn;
  21040. let isBelowFn;
  21041. let isAboveFn;
  21042. let caretPosition;
  21043. const result = [];
  21044. let line = 0;
  21045. if (direction === 1) {
  21046. walkFn = caretWalker.next;
  21047. isBelowFn = isBelow$1;
  21048. isAboveFn = isAbove$1;
  21049. caretPosition = CaretPosition.after(node);
  21050. } else {
  21051. walkFn = caretWalker.prev;
  21052. isBelowFn = isAbove$1;
  21053. isAboveFn = isBelow$1;
  21054. caretPosition = CaretPosition.before(node);
  21055. }
  21056. const targetClientRect = getLastClientRect(caretPosition);
  21057. do {
  21058. if (!caretPosition.isVisible()) {
  21059. continue;
  21060. }
  21061. const rect = getLastClientRect(caretPosition);
  21062. if (isAboveFn(rect, targetClientRect)) {
  21063. continue;
  21064. }
  21065. if (result.length > 0 && isBelowFn(rect, last$2(result))) {
  21066. line++;
  21067. }
  21068. const clientRect = clone$1(rect);
  21069. clientRect.position = caretPosition;
  21070. clientRect.line = line;
  21071. if (predicateFn(clientRect)) {
  21072. return result;
  21073. }
  21074. result.push(clientRect);
  21075. } while (caretPosition = walkFn(caretPosition));
  21076. return result;
  21077. };
  21078. const isAboveLine = lineNumber => clientRect => aboveLineNumber(lineNumber, clientRect);
  21079. const isLine = lineNumber => clientRect => isLineNumber(lineNumber, clientRect);
  21080. const moveToRange = (editor, rng) => {
  21081. editor.selection.setRng(rng);
  21082. scrollRangeIntoView(editor, editor.selection.getRng());
  21083. };
  21084. const renderRangeCaretOpt = (editor, range, scrollIntoView) => Optional.some(renderRangeCaret(editor, range, scrollIntoView));
  21085. const moveHorizontally = (editor, direction, range, isBefore, isAfter, isElement) => {
  21086. const forwards = direction === HDirection.Forwards;
  21087. const caretWalker = CaretWalker(editor.getBody());
  21088. const getNextPosFn = curry(getVisualCaretPosition, forwards ? caretWalker.next : caretWalker.prev);
  21089. const isBeforeFn = forwards ? isBefore : isAfter;
  21090. if (!range.collapsed) {
  21091. const node = getSelectedNode(range);
  21092. if (isElement(node)) {
  21093. return showCaret(direction, editor, node, direction === HDirection.Backwards, false);
  21094. } else if (isCefAtEdgeSelected(editor)) {
  21095. const newRange = range.cloneRange();
  21096. newRange.collapse(direction === HDirection.Backwards);
  21097. return Optional.from(newRange);
  21098. }
  21099. }
  21100. const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
  21101. if (isBeforeFn(caretPosition)) {
  21102. return selectNode(editor, caretPosition.getNode(!forwards));
  21103. }
  21104. let nextCaretPosition = getNextPosFn(caretPosition);
  21105. const rangeIsInContainerBlock = isRangeInCaretContainerBlock(range);
  21106. if (!nextCaretPosition) {
  21107. return rangeIsInContainerBlock ? Optional.some(range) : Optional.none();
  21108. } else {
  21109. nextCaretPosition = normalizePosition(forwards, nextCaretPosition);
  21110. }
  21111. if (isBeforeFn(nextCaretPosition)) {
  21112. return showCaret(direction, editor, nextCaretPosition.getNode(!forwards), forwards, false);
  21113. }
  21114. const peekCaretPosition = getNextPosFn(nextCaretPosition);
  21115. if (peekCaretPosition && isBeforeFn(peekCaretPosition)) {
  21116. if (isMoveInsideSameBlock(nextCaretPosition, peekCaretPosition)) {
  21117. return showCaret(direction, editor, peekCaretPosition.getNode(!forwards), forwards, false);
  21118. }
  21119. }
  21120. if (rangeIsInContainerBlock) {
  21121. return renderRangeCaretOpt(editor, nextCaretPosition.toRange(), false);
  21122. }
  21123. return Optional.none();
  21124. };
  21125. const moveVertically = (editor, direction, range, isBefore, isAfter, isElement) => {
  21126. const caretPosition = getNormalizedRangeEndPoint(direction, editor.getBody(), range);
  21127. const caretClientRect = last$2(caretPosition.getClientRects());
  21128. const forwards = direction === VDirection.Down;
  21129. const root = editor.getBody();
  21130. if (!caretClientRect) {
  21131. return Optional.none();
  21132. }
  21133. if (isCefAtEdgeSelected(editor)) {
  21134. const caretPosition = forwards ? CaretPosition.fromRangeEnd(range) : CaretPosition.fromRangeStart(range);
  21135. const getClosestFn = !forwards ? getClosestPositionAbove : getClosestPositionBelow;
  21136. return getClosestFn(root, caretPosition).orThunk(() => Optional.from(caretPosition)).map(pos => pos.toRange());
  21137. }
  21138. const walkerFn = forwards ? downUntil : upUntil;
  21139. const linePositions = walkerFn(root, isAboveLine(1), caretPosition);
  21140. const nextLinePositions = filter$5(linePositions, isLine(1));
  21141. const clientX = caretClientRect.left;
  21142. const nextLineRect = findClosestClientRect(nextLinePositions, clientX);
  21143. if (nextLineRect && isElement(nextLineRect.node)) {
  21144. const dist1 = Math.abs(clientX - nextLineRect.left);
  21145. const dist2 = Math.abs(clientX - nextLineRect.right);
  21146. return showCaret(direction, editor, nextLineRect.node, dist1 < dist2, false);
  21147. }
  21148. let currentNode;
  21149. if (isBefore(caretPosition)) {
  21150. currentNode = caretPosition.getNode();
  21151. } else if (isAfter(caretPosition)) {
  21152. currentNode = caretPosition.getNode(true);
  21153. } else {
  21154. currentNode = getSelectedNode(range);
  21155. }
  21156. if (currentNode) {
  21157. const caretPositions = positionsUntil(direction, root, isAboveLine(1), currentNode);
  21158. let closestNextLineRect = findClosestClientRect(filter$5(caretPositions, isLine(1)), clientX);
  21159. if (closestNextLineRect) {
  21160. return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
  21161. }
  21162. closestNextLineRect = last$2(filter$5(caretPositions, isLine(0)));
  21163. if (closestNextLineRect) {
  21164. return renderRangeCaretOpt(editor, closestNextLineRect.position.toRange(), false);
  21165. }
  21166. }
  21167. if (nextLinePositions.length === 0) {
  21168. return getLineEndPoint(editor, forwards).filter(forwards ? isAfter : isBefore).map(pos => renderRangeCaret(editor, pos.toRange(), false));
  21169. }
  21170. return Optional.none();
  21171. };
  21172. const getLineEndPoint = (editor, forward) => {
  21173. const rng = editor.selection.getRng();
  21174. const from = forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
  21175. const host = getEditingHost(from.container(), editor.getBody());
  21176. if (forward) {
  21177. const lineInfo = getPositionsUntilNextLine(host, from);
  21178. return last$3(lineInfo.positions);
  21179. } else {
  21180. const lineInfo = getPositionsUntilPreviousLine(host, from);
  21181. return head(lineInfo.positions);
  21182. }
  21183. };
  21184. const moveToLineEndPoint$3 = (editor, forward, isElementPosition) => getLineEndPoint(editor, forward).filter(isElementPosition).exists(pos => {
  21185. editor.selection.setRng(pos.toRange());
  21186. return true;
  21187. });
  21188. const setCaretPosition = (editor, pos) => {
  21189. const rng = editor.dom.createRng();
  21190. rng.setStart(pos.container(), pos.offset());
  21191. rng.setEnd(pos.container(), pos.offset());
  21192. editor.selection.setRng(rng);
  21193. };
  21194. const setSelected = (state, elm) => {
  21195. if (state) {
  21196. elm.setAttribute('data-mce-selected', 'inline-boundary');
  21197. } else {
  21198. elm.removeAttribute('data-mce-selected');
  21199. }
  21200. };
  21201. const renderCaretLocation = (editor, caret, location) => renderCaret(caret, location).map(pos => {
  21202. setCaretPosition(editor, pos);
  21203. return location;
  21204. });
  21205. const getPositionFromRange = (range, root, forward) => {
  21206. const start = CaretPosition.fromRangeStart(range);
  21207. if (range.collapsed) {
  21208. return start;
  21209. } else {
  21210. const end = CaretPosition.fromRangeEnd(range);
  21211. return forward ? prevPosition(root, end).getOr(end) : nextPosition(root, start).getOr(start);
  21212. }
  21213. };
  21214. const findLocation = (editor, caret, forward) => {
  21215. const rootNode = editor.getBody();
  21216. const from = getPositionFromRange(editor.selection.getRng(), rootNode, forward);
  21217. const isInlineTarget$1 = curry(isInlineTarget, editor);
  21218. const location = findLocation$1(forward, isInlineTarget$1, rootNode, from);
  21219. return location.bind(location => renderCaretLocation(editor, caret, location));
  21220. };
  21221. const toggleInlines = (isInlineTarget, dom, elms) => {
  21222. const inlineBoundaries = map$3(descendants(SugarElement.fromDom(dom.getRoot()), '*[data-mce-selected="inline-boundary"]'), e => e.dom);
  21223. const selectedInlines = filter$5(inlineBoundaries, isInlineTarget);
  21224. const targetInlines = filter$5(elms, isInlineTarget);
  21225. each$e(difference(selectedInlines, targetInlines), curry(setSelected, false));
  21226. each$e(difference(targetInlines, selectedInlines), curry(setSelected, true));
  21227. };
  21228. const safeRemoveCaretContainer = (editor, caret) => {
  21229. const caretValue = caret.get();
  21230. if (editor.selection.isCollapsed() && !editor.composing && caretValue) {
  21231. const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
  21232. if (CaretPosition.isTextPosition(pos) && !isAtZwsp(pos)) {
  21233. setCaretPosition(editor, removeAndReposition(caretValue, pos));
  21234. caret.set(null);
  21235. }
  21236. }
  21237. };
  21238. const renderInsideInlineCaret = (isInlineTarget, editor, caret, elms) => {
  21239. if (editor.selection.isCollapsed()) {
  21240. const inlines = filter$5(elms, isInlineTarget);
  21241. each$e(inlines, _inline => {
  21242. const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
  21243. readLocation(isInlineTarget, editor.getBody(), pos).bind(location => renderCaretLocation(editor, caret, location));
  21244. });
  21245. }
  21246. };
  21247. const move$2 = (editor, caret, forward) => isInlineBoundariesEnabled(editor) ? findLocation(editor, caret, forward).isSome() : false;
  21248. const moveWord = (forward, editor, _caret) => isInlineBoundariesEnabled(editor) ? moveByWord(forward, editor) : false;
  21249. const setupSelectedState = editor => {
  21250. const caret = Cell(null);
  21251. const isInlineTarget$1 = curry(isInlineTarget, editor);
  21252. editor.on('NodeChange', e => {
  21253. if (isInlineBoundariesEnabled(editor)) {
  21254. toggleInlines(isInlineTarget$1, editor.dom, e.parents);
  21255. safeRemoveCaretContainer(editor, caret);
  21256. renderInsideInlineCaret(isInlineTarget$1, editor, caret, e.parents);
  21257. }
  21258. });
  21259. return caret;
  21260. };
  21261. const moveNextWord = curry(moveWord, true);
  21262. const movePrevWord = curry(moveWord, false);
  21263. const moveToLineEndPoint$2 = (editor, forward, caret) => {
  21264. if (isInlineBoundariesEnabled(editor)) {
  21265. const linePoint = getLineEndPoint(editor, forward).getOrThunk(() => {
  21266. const rng = editor.selection.getRng();
  21267. return forward ? CaretPosition.fromRangeEnd(rng) : CaretPosition.fromRangeStart(rng);
  21268. });
  21269. return readLocation(curry(isInlineTarget, editor), editor.getBody(), linePoint).exists(loc => {
  21270. const outsideLoc = outside(loc);
  21271. return renderCaret(caret, outsideLoc).exists(pos => {
  21272. setCaretPosition(editor, pos);
  21273. return true;
  21274. });
  21275. });
  21276. } else {
  21277. return false;
  21278. }
  21279. };
  21280. const rangeFromPositions = (from, to) => {
  21281. const range = document.createRange();
  21282. range.setStart(from.container(), from.offset());
  21283. range.setEnd(to.container(), to.offset());
  21284. return range;
  21285. };
  21286. const hasOnlyTwoOrLessPositionsLeft = elm => lift2(firstPositionIn(elm), lastPositionIn(elm), (firstPos, lastPos) => {
  21287. const normalizedFirstPos = normalizePosition(true, firstPos);
  21288. const normalizedLastPos = normalizePosition(false, lastPos);
  21289. return nextPosition(elm, normalizedFirstPos).forall(pos => pos.isEqual(normalizedLastPos));
  21290. }).getOr(true);
  21291. const setCaretLocation = (editor, caret) => location => renderCaret(caret, location).map(pos => () => setCaretPosition(editor, pos));
  21292. const deleteFromTo = (editor, caret, from, to) => {
  21293. const rootNode = editor.getBody();
  21294. const isInlineTarget$1 = curry(isInlineTarget, editor);
  21295. editor.undoManager.ignore(() => {
  21296. editor.selection.setRng(rangeFromPositions(from, to));
  21297. execNativeDeleteCommand(editor);
  21298. readLocation(isInlineTarget$1, rootNode, CaretPosition.fromRangeStart(editor.selection.getRng())).map(inside).bind(setCaretLocation(editor, caret)).each(call);
  21299. });
  21300. editor.nodeChanged();
  21301. };
  21302. const rescope = (rootNode, node) => {
  21303. const parentBlock = getParentBlock$3(node, rootNode);
  21304. return parentBlock ? parentBlock : rootNode;
  21305. };
  21306. const backspaceDeleteCollapsed = (editor, caret, forward, from) => {
  21307. const rootNode = rescope(editor.getBody(), from.container());
  21308. const isInlineTarget$1 = curry(isInlineTarget, editor);
  21309. const fromLocation = readLocation(isInlineTarget$1, rootNode, from);
  21310. const location = fromLocation.bind(location => {
  21311. if (forward) {
  21312. return location.fold(constant(Optional.some(inside(location))), Optional.none, constant(Optional.some(outside(location))), Optional.none);
  21313. } else {
  21314. return location.fold(Optional.none, constant(Optional.some(outside(location))), Optional.none, constant(Optional.some(inside(location))));
  21315. }
  21316. });
  21317. return location.map(setCaretLocation(editor, caret)).getOrThunk(() => {
  21318. const toPosition = navigate(forward, rootNode, from);
  21319. const toLocation = toPosition.bind(pos => readLocation(isInlineTarget$1, rootNode, pos));
  21320. return lift2(fromLocation, toLocation, () => findRootInline(isInlineTarget$1, rootNode, from).bind(elm => {
  21321. if (hasOnlyTwoOrLessPositionsLeft(elm)) {
  21322. return Optional.some(() => {
  21323. deleteElement$2(editor, forward, SugarElement.fromDom(elm));
  21324. });
  21325. } else {
  21326. return Optional.none();
  21327. }
  21328. })).getOrThunk(() => toLocation.bind(() => toPosition.map(to => {
  21329. return () => {
  21330. if (forward) {
  21331. deleteFromTo(editor, caret, from, to);
  21332. } else {
  21333. deleteFromTo(editor, caret, to, from);
  21334. }
  21335. };
  21336. })));
  21337. });
  21338. };
  21339. const backspaceDelete$3 = (editor, caret, forward) => {
  21340. if (editor.selection.isCollapsed() && isInlineBoundariesEnabled(editor)) {
  21341. const from = CaretPosition.fromRangeStart(editor.selection.getRng());
  21342. return backspaceDeleteCollapsed(editor, caret, forward, from);
  21343. }
  21344. return Optional.none();
  21345. };
  21346. const getParentInlines = (rootElm, startElm) => {
  21347. const parents = parentsAndSelf(startElm, rootElm);
  21348. return findIndex$2(parents, isBlock$2).fold(constant(parents), index => parents.slice(0, index));
  21349. };
  21350. const hasOnlyOneChild = elm => childNodesCount(elm) === 1;
  21351. const deleteLastPosition = (forward, editor, target, parentInlines) => {
  21352. const isFormatElement$1 = curry(isFormatElement, editor);
  21353. const formatNodes = map$3(filter$5(parentInlines, isFormatElement$1), elm => elm.dom);
  21354. if (formatNodes.length === 0) {
  21355. deleteElement$2(editor, forward, target);
  21356. } else {
  21357. const pos = replaceWithCaretFormat(target.dom, formatNodes);
  21358. editor.selection.setRng(pos.toRange());
  21359. }
  21360. };
  21361. const deleteCaret$1 = (editor, forward) => {
  21362. const rootElm = SugarElement.fromDom(editor.getBody());
  21363. const startElm = SugarElement.fromDom(editor.selection.getStart());
  21364. const parentInlines = filter$5(getParentInlines(rootElm, startElm), hasOnlyOneChild);
  21365. return last$3(parentInlines).bind(target => {
  21366. const fromPos = CaretPosition.fromRangeStart(editor.selection.getRng());
  21367. if (willDeleteLastPositionInElement(forward, fromPos, target.dom) && !isEmptyCaretFormatElement(target)) {
  21368. return Optional.some(() => deleteLastPosition(forward, editor, target, parentInlines));
  21369. } else {
  21370. return Optional.none();
  21371. }
  21372. });
  21373. };
  21374. const backspaceDelete$2 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret$1(editor, forward) : Optional.none();
  21375. const deleteElement = (editor, forward, element) => {
  21376. if (isNonNullable(element)) {
  21377. return Optional.some(() => {
  21378. editor._selectionOverrides.hideFakeCaret();
  21379. deleteElement$2(editor, forward, SugarElement.fromDom(element));
  21380. });
  21381. } else {
  21382. return Optional.none();
  21383. }
  21384. };
  21385. const deleteCaret = (editor, forward) => {
  21386. const isNearMedia = forward ? isBeforeMedia : isAfterMedia;
  21387. const direction = forward ? HDirection.Forwards : HDirection.Backwards;
  21388. const fromPos = getNormalizedRangeEndPoint(direction, editor.getBody(), editor.selection.getRng());
  21389. if (isNearMedia(fromPos)) {
  21390. return deleteElement(editor, forward, fromPos.getNode(!forward));
  21391. } else {
  21392. return Optional.from(normalizePosition(forward, fromPos)).filter(pos => isNearMedia(pos) && isMoveInsideSameBlock(fromPos, pos)).bind(pos => deleteElement(editor, forward, pos.getNode(!forward)));
  21393. }
  21394. };
  21395. const deleteRange = (editor, forward) => {
  21396. const selectedNode = editor.selection.getNode();
  21397. return isMedia$2(selectedNode) ? deleteElement(editor, forward, selectedNode) : Optional.none();
  21398. };
  21399. const backspaceDelete$1 = (editor, forward) => editor.selection.isCollapsed() ? deleteCaret(editor, forward) : deleteRange(editor, forward);
  21400. const isEditable$1 = target => closest$4(target, elm => isContentEditableTrue$3(elm.dom) || isContentEditableFalse$a(elm.dom)).exists(elm => isContentEditableTrue$3(elm.dom));
  21401. const parseIndentValue = value => toInt(value !== null && value !== void 0 ? value : '').getOr(0);
  21402. const getIndentStyleName = (useMargin, element) => {
  21403. const indentStyleName = useMargin || isTable$1(element) ? 'margin' : 'padding';
  21404. const suffix = get$7(element, 'direction') === 'rtl' ? '-right' : '-left';
  21405. return indentStyleName + suffix;
  21406. };
  21407. const indentElement = (dom, command, useMargin, value, unit, element) => {
  21408. const indentStyleName = getIndentStyleName(useMargin, SugarElement.fromDom(element));
  21409. const parsedValue = parseIndentValue(dom.getStyle(element, indentStyleName));
  21410. if (command === 'outdent') {
  21411. const styleValue = Math.max(0, parsedValue - value);
  21412. dom.setStyle(element, indentStyleName, styleValue ? styleValue + unit : '');
  21413. } else {
  21414. const styleValue = parsedValue + value + unit;
  21415. dom.setStyle(element, indentStyleName, styleValue);
  21416. }
  21417. };
  21418. const validateBlocks = (editor, blocks) => forall(blocks, block => {
  21419. const indentStyleName = getIndentStyleName(shouldIndentUseMargin(editor), block);
  21420. const intentValue = getRaw$1(block, indentStyleName).map(parseIndentValue).getOr(0);
  21421. const contentEditable = editor.dom.getContentEditable(block.dom);
  21422. return contentEditable !== 'false' && intentValue > 0;
  21423. });
  21424. const canOutdent = editor => {
  21425. const blocks = getBlocksToIndent(editor);
  21426. return !editor.mode.isReadOnly() && (blocks.length > 1 || validateBlocks(editor, blocks));
  21427. };
  21428. const isListComponent = el => isList(el) || isListItem$1(el);
  21429. const parentIsListComponent = el => parent(el).exists(isListComponent);
  21430. const getBlocksToIndent = editor => filter$5(fromDom$1(editor.selection.getSelectedBlocks()), el => !isListComponent(el) && !parentIsListComponent(el) && isEditable$1(el));
  21431. const handle = (editor, command) => {
  21432. var _a, _b;
  21433. const {dom} = editor;
  21434. const indentation = getIndentation(editor);
  21435. const indentUnit = (_b = (_a = /[a-z%]+$/i.exec(indentation)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : 'px';
  21436. const indentValue = parseIndentValue(indentation);
  21437. const useMargin = shouldIndentUseMargin(editor);
  21438. each$e(getBlocksToIndent(editor), block => {
  21439. indentElement(dom, command, useMargin, indentValue, indentUnit, block.dom);
  21440. });
  21441. };
  21442. const indent = editor => handle(editor, 'indent');
  21443. const outdent = editor => handle(editor, 'outdent');
  21444. const backspaceDelete = editor => {
  21445. if (editor.selection.isCollapsed() && canOutdent(editor)) {
  21446. const dom = editor.dom;
  21447. const rng = editor.selection.getRng();
  21448. const pos = CaretPosition.fromRangeStart(rng);
  21449. const block = dom.getParent(rng.startContainer, dom.isBlock);
  21450. if (block !== null && isAtStartOfBlock(SugarElement.fromDom(block), pos)) {
  21451. return Optional.some(() => outdent(editor));
  21452. }
  21453. }
  21454. return Optional.none();
  21455. };
  21456. const findAction = (editor, caret, forward) => findMap([
  21457. backspaceDelete,
  21458. backspaceDelete$5,
  21459. backspaceDelete$6,
  21460. (editor, forward) => backspaceDelete$3(editor, caret, forward),
  21461. backspaceDelete$8,
  21462. backspaceDelete$9,
  21463. backspaceDelete$4,
  21464. backspaceDelete$1,
  21465. backspaceDelete$7,
  21466. backspaceDelete$2
  21467. ], item => item(editor, forward));
  21468. const deleteCommand = (editor, caret) => {
  21469. const result = findAction(editor, caret, false);
  21470. result.fold(() => {
  21471. execNativeDeleteCommand(editor);
  21472. paddEmptyBody(editor);
  21473. }, call);
  21474. };
  21475. const forwardDeleteCommand = (editor, caret) => {
  21476. const result = findAction(editor, caret, true);
  21477. result.fold(() => execNativeForwardDeleteCommand(editor), call);
  21478. };
  21479. const setup$p = (editor, caret) => {
  21480. editor.addCommand('delete', () => {
  21481. deleteCommand(editor, caret);
  21482. });
  21483. editor.addCommand('forwardDelete', () => {
  21484. forwardDeleteCommand(editor, caret);
  21485. });
  21486. };
  21487. const SIGNIFICANT_MOVE = 5;
  21488. const LONGPRESS_DELAY = 400;
  21489. const getTouch = event => {
  21490. if (event.touches === undefined || event.touches.length !== 1) {
  21491. return Optional.none();
  21492. }
  21493. return Optional.some(event.touches[0]);
  21494. };
  21495. const isFarEnough = (touch, data) => {
  21496. const distX = Math.abs(touch.clientX - data.x);
  21497. const distY = Math.abs(touch.clientY - data.y);
  21498. return distX > SIGNIFICANT_MOVE || distY > SIGNIFICANT_MOVE;
  21499. };
  21500. const setup$o = editor => {
  21501. const startData = value$2();
  21502. const longpressFired = Cell(false);
  21503. const debounceLongpress = last$1(e => {
  21504. editor.dispatch('longpress', {
  21505. ...e,
  21506. type: 'longpress'
  21507. });
  21508. longpressFired.set(true);
  21509. }, LONGPRESS_DELAY);
  21510. editor.on('touchstart', e => {
  21511. getTouch(e).each(touch => {
  21512. debounceLongpress.cancel();
  21513. const data = {
  21514. x: touch.clientX,
  21515. y: touch.clientY,
  21516. target: e.target
  21517. };
  21518. debounceLongpress.throttle(e);
  21519. longpressFired.set(false);
  21520. startData.set(data);
  21521. });
  21522. }, true);
  21523. editor.on('touchmove', e => {
  21524. debounceLongpress.cancel();
  21525. getTouch(e).each(touch => {
  21526. startData.on(data => {
  21527. if (isFarEnough(touch, data)) {
  21528. startData.clear();
  21529. longpressFired.set(false);
  21530. editor.dispatch('longpresscancel');
  21531. }
  21532. });
  21533. });
  21534. }, true);
  21535. editor.on('touchend touchcancel', e => {
  21536. debounceLongpress.cancel();
  21537. if (e.type === 'touchcancel') {
  21538. return;
  21539. }
  21540. startData.get().filter(data => data.target.isEqualNode(e.target)).each(() => {
  21541. if (longpressFired.get()) {
  21542. e.preventDefault();
  21543. } else {
  21544. editor.dispatch('tap', {
  21545. ...e,
  21546. type: 'tap'
  21547. });
  21548. }
  21549. });
  21550. }, true);
  21551. };
  21552. const isBlockElement = (blockElements, node) => has$2(blockElements, node.nodeName);
  21553. const isValidTarget = (schema, node) => {
  21554. if (isText$a(node)) {
  21555. return true;
  21556. } else if (isElement$6(node)) {
  21557. return !isBlockElement(schema.getBlockElements(), node) && !isBookmarkNode$1(node) && !isTransparentBlock(schema, node);
  21558. } else {
  21559. return false;
  21560. }
  21561. };
  21562. const hasBlockParent = (blockElements, root, node) => {
  21563. return exists(parents(SugarElement.fromDom(node), SugarElement.fromDom(root)), elm => {
  21564. return isBlockElement(blockElements, elm.dom);
  21565. });
  21566. };
  21567. const shouldRemoveTextNode = (blockElements, node) => {
  21568. if (isText$a(node)) {
  21569. if (node.data.length === 0) {
  21570. return true;
  21571. } else if (/^\s+$/.test(node.data) && (!node.nextSibling || isBlockElement(blockElements, node.nextSibling))) {
  21572. return true;
  21573. }
  21574. }
  21575. return false;
  21576. };
  21577. const createRootBlock = editor => editor.dom.create(getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
  21578. const addRootBlocks = editor => {
  21579. const dom = editor.dom, selection = editor.selection;
  21580. const schema = editor.schema;
  21581. const blockElements = schema.getBlockElements();
  21582. const startNode = selection.getStart();
  21583. const rootNode = editor.getBody();
  21584. let rootBlockNode;
  21585. let tempNode;
  21586. let wrapped = false;
  21587. const forcedRootBlock = getForcedRootBlock(editor);
  21588. if (!startNode || !isElement$6(startNode)) {
  21589. return;
  21590. }
  21591. const rootNodeName = rootNode.nodeName.toLowerCase();
  21592. if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, startNode)) {
  21593. return;
  21594. }
  21595. const rng = selection.getRng();
  21596. const {startContainer, startOffset, endContainer, endOffset} = rng;
  21597. const restoreSelection = hasFocus(editor);
  21598. let node = rootNode.firstChild;
  21599. while (node) {
  21600. if (isElement$6(node)) {
  21601. updateElement(schema, node);
  21602. }
  21603. if (isValidTarget(schema, node)) {
  21604. if (shouldRemoveTextNode(blockElements, node)) {
  21605. tempNode = node;
  21606. node = node.nextSibling;
  21607. dom.remove(tempNode);
  21608. continue;
  21609. }
  21610. if (!rootBlockNode) {
  21611. rootBlockNode = createRootBlock(editor);
  21612. rootNode.insertBefore(rootBlockNode, node);
  21613. wrapped = true;
  21614. }
  21615. tempNode = node;
  21616. node = node.nextSibling;
  21617. rootBlockNode.appendChild(tempNode);
  21618. } else {
  21619. rootBlockNode = null;
  21620. node = node.nextSibling;
  21621. }
  21622. }
  21623. if (wrapped && restoreSelection) {
  21624. rng.setStart(startContainer, startOffset);
  21625. rng.setEnd(endContainer, endOffset);
  21626. selection.setRng(rng);
  21627. editor.nodeChanged();
  21628. }
  21629. };
  21630. const insertEmptyLine = (editor, root, insertBlock) => {
  21631. const block = SugarElement.fromDom(createRootBlock(editor));
  21632. const br = createPaddingBr();
  21633. append$1(block, br);
  21634. insertBlock(root, block);
  21635. const rng = document.createRange();
  21636. rng.setStartBefore(br.dom);
  21637. rng.setEndBefore(br.dom);
  21638. return rng;
  21639. };
  21640. const setup$n = editor => {
  21641. editor.on('NodeChange', curry(addRootBlocks, editor));
  21642. };
  21643. const hasClass = checkClassName => node => (' ' + node.attr('class') + ' ').indexOf(checkClassName) !== -1;
  21644. const replaceMatchWithSpan = (editor, content, cls) => {
  21645. return function (match) {
  21646. const args = arguments, index = args[args.length - 2];
  21647. const prevChar = index > 0 ? content.charAt(index - 1) : '';
  21648. if (prevChar === '"') {
  21649. return match;
  21650. }
  21651. if (prevChar === '>') {
  21652. const findStartTagIndex = content.lastIndexOf('<', index);
  21653. if (findStartTagIndex !== -1) {
  21654. const tagHtml = content.substring(findStartTagIndex, index);
  21655. if (tagHtml.indexOf('contenteditable="false"') !== -1) {
  21656. return match;
  21657. }
  21658. }
  21659. }
  21660. return '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' + editor.dom.encode(typeof args[1] === 'string' ? args[1] : args[0]) + '</span>';
  21661. };
  21662. };
  21663. const convertRegExpsToNonEditable = (editor, nonEditableRegExps, e) => {
  21664. let i = nonEditableRegExps.length, content = e.content;
  21665. if (e.format === 'raw') {
  21666. return;
  21667. }
  21668. while (i--) {
  21669. content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan(editor, content, getNonEditableClass(editor)));
  21670. }
  21671. e.content = content;
  21672. };
  21673. const setup$m = editor => {
  21674. const contentEditableAttrName = 'contenteditable';
  21675. const editClass = ' ' + Tools.trim(getEditableClass(editor)) + ' ';
  21676. const nonEditClass = ' ' + Tools.trim(getNonEditableClass(editor)) + ' ';
  21677. const hasEditClass = hasClass(editClass);
  21678. const hasNonEditClass = hasClass(nonEditClass);
  21679. const nonEditableRegExps = getNonEditableRegExps(editor);
  21680. if (nonEditableRegExps.length > 0) {
  21681. editor.on('BeforeSetContent', e => {
  21682. convertRegExpsToNonEditable(editor, nonEditableRegExps, e);
  21683. });
  21684. }
  21685. editor.parser.addAttributeFilter('class', nodes => {
  21686. let i = nodes.length;
  21687. while (i--) {
  21688. const node = nodes[i];
  21689. if (hasEditClass(node)) {
  21690. node.attr(contentEditableAttrName, 'true');
  21691. } else if (hasNonEditClass(node)) {
  21692. node.attr(contentEditableAttrName, 'false');
  21693. }
  21694. }
  21695. });
  21696. editor.serializer.addAttributeFilter(contentEditableAttrName, nodes => {
  21697. let i = nodes.length;
  21698. while (i--) {
  21699. const node = nodes[i];
  21700. if (!hasEditClass(node) && !hasNonEditClass(node)) {
  21701. continue;
  21702. }
  21703. if (nonEditableRegExps.length > 0 && node.attr('data-mce-content')) {
  21704. node.name = '#text';
  21705. node.type = 3;
  21706. node.raw = true;
  21707. node.value = node.attr('data-mce-content');
  21708. } else {
  21709. node.attr(contentEditableAttrName, null);
  21710. }
  21711. }
  21712. });
  21713. };
  21714. const findBlockCaretContainer = editor => descendant(SugarElement.fromDom(editor.getBody()), '*[data-mce-caret]').map(elm => elm.dom).getOrNull();
  21715. const showBlockCaretContainer = (editor, blockCaretContainer) => {
  21716. if (blockCaretContainer.hasAttribute('data-mce-caret')) {
  21717. showCaretContainerBlock(blockCaretContainer);
  21718. editor.selection.setRng(editor.selection.getRng());
  21719. editor.selection.scrollIntoView(blockCaretContainer);
  21720. }
  21721. };
  21722. const handleBlockContainer = (editor, e) => {
  21723. const blockCaretContainer = findBlockCaretContainer(editor);
  21724. if (!blockCaretContainer) {
  21725. return;
  21726. }
  21727. if (e.type === 'compositionstart') {
  21728. e.preventDefault();
  21729. e.stopPropagation();
  21730. showBlockCaretContainer(editor, blockCaretContainer);
  21731. return;
  21732. }
  21733. if (hasContent(blockCaretContainer)) {
  21734. showBlockCaretContainer(editor, blockCaretContainer);
  21735. editor.undoManager.add();
  21736. }
  21737. };
  21738. const setup$l = editor => {
  21739. editor.on('keyup compositionstart', curry(handleBlockContainer, editor));
  21740. };
  21741. const isContentEditableFalse$3 = isContentEditableFalse$a;
  21742. const moveToCeFalseHorizontally = (direction, editor, range) => moveHorizontally(editor, direction, range, isBeforeContentEditableFalse, isAfterContentEditableFalse, isContentEditableFalse$3);
  21743. const moveToCeFalseVertically = (direction, editor, range) => {
  21744. const isBefore = caretPosition => isBeforeContentEditableFalse(caretPosition) || isBeforeTable(caretPosition);
  21745. const isAfter = caretPosition => isAfterContentEditableFalse(caretPosition) || isAfterTable(caretPosition);
  21746. return moveVertically(editor, direction, range, isBefore, isAfter, isContentEditableFalse$3);
  21747. };
  21748. const createTextBlock = editor => {
  21749. const textBlock = editor.dom.create(getForcedRootBlock(editor));
  21750. textBlock.innerHTML = '<br data-mce-bogus="1">';
  21751. return textBlock;
  21752. };
  21753. const exitPreBlock = (editor, direction, range) => {
  21754. const caretWalker = CaretWalker(editor.getBody());
  21755. const getVisualCaretPosition$1 = curry(getVisualCaretPosition, direction === 1 ? caretWalker.next : caretWalker.prev);
  21756. if (range.collapsed) {
  21757. const pre = editor.dom.getParent(range.startContainer, 'PRE');
  21758. if (!pre) {
  21759. return;
  21760. }
  21761. const caretPos = getVisualCaretPosition$1(CaretPosition.fromRangeStart(range));
  21762. if (!caretPos) {
  21763. const newBlock = SugarElement.fromDom(createTextBlock(editor));
  21764. if (direction === 1) {
  21765. after$4(SugarElement.fromDom(pre), newBlock);
  21766. } else {
  21767. before$3(SugarElement.fromDom(pre), newBlock);
  21768. }
  21769. editor.selection.select(newBlock.dom, true);
  21770. editor.selection.collapse();
  21771. }
  21772. }
  21773. };
  21774. const getHorizontalRange = (editor, forward) => {
  21775. const direction = forward ? HDirection.Forwards : HDirection.Backwards;
  21776. const range = editor.selection.getRng();
  21777. return moveToCeFalseHorizontally(direction, editor, range).orThunk(() => {
  21778. exitPreBlock(editor, direction, range);
  21779. return Optional.none();
  21780. });
  21781. };
  21782. const getVerticalRange = (editor, down) => {
  21783. const direction = down ? 1 : -1;
  21784. const range = editor.selection.getRng();
  21785. return moveToCeFalseVertically(direction, editor, range).orThunk(() => {
  21786. exitPreBlock(editor, direction, range);
  21787. return Optional.none();
  21788. });
  21789. };
  21790. const moveH$2 = (editor, forward) => getHorizontalRange(editor, forward).exists(newRange => {
  21791. moveToRange(editor, newRange);
  21792. return true;
  21793. });
  21794. const moveV$3 = (editor, down) => getVerticalRange(editor, down).exists(newRange => {
  21795. moveToRange(editor, newRange);
  21796. return true;
  21797. });
  21798. const moveToLineEndPoint$1 = (editor, forward) => {
  21799. const isCefPosition = forward ? isAfterContentEditableFalse : isBeforeContentEditableFalse;
  21800. return moveToLineEndPoint$3(editor, forward, isCefPosition);
  21801. };
  21802. const selectToEndPoint = (editor, forward) => getEdgeCefPosition(editor, !forward).map(pos => {
  21803. const rng = pos.toRange();
  21804. const curRng = editor.selection.getRng();
  21805. if (forward) {
  21806. rng.setStart(curRng.startContainer, curRng.startOffset);
  21807. } else {
  21808. rng.setEnd(curRng.endContainer, curRng.endOffset);
  21809. }
  21810. return rng;
  21811. }).exists(rng => {
  21812. moveToRange(editor, rng);
  21813. return true;
  21814. });
  21815. const isTarget = node => contains$2(['figcaption'], name(node));
  21816. const getClosestTargetBlock = (pos, root) => {
  21817. const isRoot = curry(eq, root);
  21818. return closest$4(SugarElement.fromDom(pos.container()), isBlock$2, isRoot).filter(isTarget);
  21819. };
  21820. const isAtFirstOrLastLine = (root, forward, pos) => forward ? isAtLastLine(root.dom, pos) : isAtFirstLine(root.dom, pos);
  21821. const moveCaretToNewEmptyLine = (editor, forward) => {
  21822. const root = SugarElement.fromDom(editor.getBody());
  21823. const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
  21824. return getClosestTargetBlock(pos, root).exists(() => {
  21825. if (isAtFirstOrLastLine(root, forward, pos)) {
  21826. const insertFn = forward ? append$1 : prepend;
  21827. const rng = insertEmptyLine(editor, root, insertFn);
  21828. editor.selection.setRng(rng);
  21829. return true;
  21830. } else {
  21831. return false;
  21832. }
  21833. });
  21834. };
  21835. const moveV$2 = (editor, forward) => {
  21836. if (editor.selection.isCollapsed()) {
  21837. return moveCaretToNewEmptyLine(editor, forward);
  21838. } else {
  21839. return false;
  21840. }
  21841. };
  21842. const baseKeyPattern = {
  21843. shiftKey: false,
  21844. altKey: false,
  21845. ctrlKey: false,
  21846. metaKey: false,
  21847. keyCode: 0
  21848. };
  21849. const defaultPatterns = patterns => map$3(patterns, pattern => ({
  21850. ...baseKeyPattern,
  21851. ...pattern
  21852. }));
  21853. const defaultDelayedPatterns = patterns => map$3(patterns, pattern => ({
  21854. ...baseKeyPattern,
  21855. ...pattern
  21856. }));
  21857. const matchesEvent = (pattern, evt) => evt.keyCode === pattern.keyCode && evt.shiftKey === pattern.shiftKey && evt.altKey === pattern.altKey && evt.ctrlKey === pattern.ctrlKey && evt.metaKey === pattern.metaKey;
  21858. const match$1 = (patterns, evt) => bind$3(defaultPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
  21859. const matchDelayed = (patterns, evt) => bind$3(defaultDelayedPatterns(patterns), pattern => matchesEvent(pattern, evt) ? [pattern] : []);
  21860. const action = (f, ...x) => () => f.apply(null, x);
  21861. const execute = (patterns, evt) => find$2(match$1(patterns, evt), pattern => pattern.action());
  21862. const executeWithDelayedAction = (patterns, evt) => findMap(matchDelayed(patterns, evt), pattern => pattern.action());
  21863. const moveH$1 = (editor, forward) => {
  21864. const direction = forward ? HDirection.Forwards : HDirection.Backwards;
  21865. const range = editor.selection.getRng();
  21866. return moveHorizontally(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
  21867. moveToRange(editor, newRange);
  21868. return true;
  21869. });
  21870. };
  21871. const moveV$1 = (editor, down) => {
  21872. const direction = down ? 1 : -1;
  21873. const range = editor.selection.getRng();
  21874. return moveVertically(editor, direction, range, isBeforeMedia, isAfterMedia, isMedia$2).exists(newRange => {
  21875. moveToRange(editor, newRange);
  21876. return true;
  21877. });
  21878. };
  21879. const moveToLineEndPoint = (editor, forward) => {
  21880. const isNearMedia = forward ? isAfterMedia : isBeforeMedia;
  21881. return moveToLineEndPoint$3(editor, forward, isNearMedia);
  21882. };
  21883. const adt = Adt.generate([
  21884. { none: ['current'] },
  21885. { first: ['current'] },
  21886. {
  21887. middle: [
  21888. 'current',
  21889. 'target'
  21890. ]
  21891. },
  21892. { last: ['current'] }
  21893. ]);
  21894. const none = current => adt.none(current);
  21895. const CellLocation = {
  21896. ...adt,
  21897. none
  21898. };
  21899. const firstLayer = (scope, selector) => {
  21900. return filterFirstLayer(scope, selector, always);
  21901. };
  21902. const filterFirstLayer = (scope, selector, predicate) => {
  21903. return bind$3(children$1(scope), x => {
  21904. if (is$1(x, selector)) {
  21905. return predicate(x) ? [x] : [];
  21906. } else {
  21907. return filterFirstLayer(x, selector, predicate);
  21908. }
  21909. });
  21910. };
  21911. const lookup$1 = (tags, element, isRoot = never) => {
  21912. if (isRoot(element)) {
  21913. return Optional.none();
  21914. }
  21915. if (contains$2(tags, name(element))) {
  21916. return Optional.some(element);
  21917. }
  21918. const isRootOrUpperTable = elm => is$1(elm, 'table') || isRoot(elm);
  21919. return ancestor$2(element, tags.join(','), isRootOrUpperTable);
  21920. };
  21921. const cell = (element, isRoot) => lookup$1([
  21922. 'td',
  21923. 'th'
  21924. ], element, isRoot);
  21925. const cells = ancestor => firstLayer(ancestor, 'th,td');
  21926. const table = (element, isRoot) => closest$3(element, 'table', isRoot);
  21927. const walk = (all, current, index, direction, isEligible = always) => {
  21928. const forwards = direction === 1;
  21929. if (!forwards && index <= 0) {
  21930. return CellLocation.first(all[0]);
  21931. } else if (forwards && index >= all.length - 1) {
  21932. return CellLocation.last(all[all.length - 1]);
  21933. } else {
  21934. const newIndex = index + direction;
  21935. const elem = all[newIndex];
  21936. return isEligible(elem) ? CellLocation.middle(current, elem) : walk(all, current, newIndex, direction, isEligible);
  21937. }
  21938. };
  21939. const detect = (current, isRoot) => {
  21940. return table(current, isRoot).bind(table => {
  21941. const all = cells(table);
  21942. const index = findIndex$2(all, x => eq(current, x));
  21943. return index.map(index => ({
  21944. index,
  21945. all
  21946. }));
  21947. });
  21948. };
  21949. const next = (current, isEligible, isRoot) => {
  21950. const detection = detect(current, isRoot);
  21951. return detection.fold(() => {
  21952. return CellLocation.none(current);
  21953. }, info => {
  21954. return walk(info.all, current, info.index, 1, isEligible);
  21955. });
  21956. };
  21957. const prev = (current, isEligible, isRoot) => {
  21958. const detection = detect(current, isRoot);
  21959. return detection.fold(() => {
  21960. return CellLocation.none();
  21961. }, info => {
  21962. return walk(info.all, current, info.index, -1, isEligible);
  21963. });
  21964. };
  21965. const closest = target => closest$3(target, '[contenteditable]');
  21966. const isEditable = (element, assumeEditable = false) => {
  21967. if (inBody(element)) {
  21968. return element.dom.isContentEditable;
  21969. } else {
  21970. return closest(element).fold(constant(assumeEditable), editable => getRaw(editable) === 'true');
  21971. }
  21972. };
  21973. const getRaw = element => element.dom.contentEditable;
  21974. const deflate = (rect, delta) => ({
  21975. left: rect.left - delta,
  21976. top: rect.top - delta,
  21977. right: rect.right + delta * 2,
  21978. bottom: rect.bottom + delta * 2,
  21979. width: rect.width + delta,
  21980. height: rect.height + delta
  21981. });
  21982. const getCorners = (getYAxisValue, tds) => bind$3(tds, td => {
  21983. const rect = deflate(clone$1(td.getBoundingClientRect()), -1);
  21984. return [
  21985. {
  21986. x: rect.left,
  21987. y: getYAxisValue(rect),
  21988. cell: td
  21989. },
  21990. {
  21991. x: rect.right,
  21992. y: getYAxisValue(rect),
  21993. cell: td
  21994. }
  21995. ];
  21996. });
  21997. const findClosestCorner = (corners, x, y) => foldl(corners, (acc, newCorner) => acc.fold(() => Optional.some(newCorner), oldCorner => {
  21998. const oldDist = Math.sqrt(Math.abs(oldCorner.x - x) + Math.abs(oldCorner.y - y));
  21999. const newDist = Math.sqrt(Math.abs(newCorner.x - x) + Math.abs(newCorner.y - y));
  22000. return Optional.some(newDist < oldDist ? newCorner : oldCorner);
  22001. }), Optional.none());
  22002. const getClosestCell = (getYAxisValue, isTargetCorner, table, x, y) => {
  22003. const cells = descendants(SugarElement.fromDom(table), 'td,th,caption').map(e => e.dom);
  22004. const corners = filter$5(getCorners(getYAxisValue, cells), corner => isTargetCorner(corner, y));
  22005. return findClosestCorner(corners, x, y).map(corner => corner.cell);
  22006. };
  22007. const getBottomValue = rect => rect.bottom;
  22008. const getTopValue = rect => rect.top;
  22009. const isAbove = (corner, y) => corner.y < y;
  22010. const isBelow = (corner, y) => corner.y > y;
  22011. const getClosestCellAbove = curry(getClosestCell, getBottomValue, isAbove);
  22012. const getClosestCellBelow = curry(getClosestCell, getTopValue, isBelow);
  22013. const findClosestPositionInAboveCell = (table, pos) => head(pos.getClientRects()).bind(rect => getClosestCellAbove(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getLastLinePositions(cell), pos));
  22014. const findClosestPositionInBelowCell = (table, pos) => last$3(pos.getClientRects()).bind(rect => getClosestCellBelow(table, rect.left, rect.top)).bind(cell => findClosestHorizontalPosition(getFirstLinePositions(cell), pos));
  22015. const hasNextBreak = (getPositionsUntil, scope, lineInfo) => lineInfo.breakAt.exists(breakPos => getPositionsUntil(scope, breakPos).breakAt.isSome());
  22016. const startsWithWrapBreak = lineInfo => lineInfo.breakType === BreakType.Wrap && lineInfo.positions.length === 0;
  22017. const startsWithBrBreak = lineInfo => lineInfo.breakType === BreakType.Br && lineInfo.positions.length === 1;
  22018. const isAtTableCellLine = (getPositionsUntil, scope, pos) => {
  22019. const lineInfo = getPositionsUntil(scope, pos);
  22020. if (startsWithWrapBreak(lineInfo) || !isBr$6(pos.getNode()) && startsWithBrBreak(lineInfo)) {
  22021. return !hasNextBreak(getPositionsUntil, scope, lineInfo);
  22022. } else {
  22023. return lineInfo.breakAt.isNone();
  22024. }
  22025. };
  22026. const isAtFirstTableCellLine = curry(isAtTableCellLine, getPositionsUntilPreviousLine);
  22027. const isAtLastTableCellLine = curry(isAtTableCellLine, getPositionsUntilNextLine);
  22028. const isCaretAtStartOrEndOfTable = (forward, rng, table) => {
  22029. const caretPos = CaretPosition.fromRangeStart(rng);
  22030. return positionIn(!forward, table).exists(pos => pos.isEqual(caretPos));
  22031. };
  22032. const navigateHorizontally = (editor, forward, table, _td) => {
  22033. const rng = editor.selection.getRng();
  22034. const direction = forward ? 1 : -1;
  22035. if (isFakeCaretTableBrowser() && isCaretAtStartOrEndOfTable(forward, rng, table)) {
  22036. showCaret(direction, editor, table, !forward, false).each(newRng => {
  22037. moveToRange(editor, newRng);
  22038. });
  22039. return true;
  22040. }
  22041. return false;
  22042. };
  22043. const getClosestAbovePosition = (root, table, start) => findClosestPositionInAboveCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsAbove(root, CaretPosition.before(table)), rect.left))).getOr(CaretPosition.before(table));
  22044. const getClosestBelowPosition = (root, table, start) => findClosestPositionInBelowCell(table, start).orThunk(() => head(start.getClientRects()).bind(rect => findClosestHorizontalPositionFromPoint(getPositionsBelow(root, CaretPosition.after(table)), rect.left))).getOr(CaretPosition.after(table));
  22045. const getTable = (previous, pos) => {
  22046. const node = pos.getNode(previous);
  22047. return isTable$2(node) ? Optional.some(node) : Optional.none();
  22048. };
  22049. const renderBlock = (down, editor, table) => {
  22050. editor.undoManager.transact(() => {
  22051. const insertFn = down ? after$4 : before$3;
  22052. const rng = insertEmptyLine(editor, SugarElement.fromDom(table), insertFn);
  22053. moveToRange(editor, rng);
  22054. });
  22055. };
  22056. const moveCaret = (editor, down, pos) => {
  22057. const table = down ? getTable(true, pos) : getTable(false, pos);
  22058. const last = down === false;
  22059. table.fold(() => moveToRange(editor, pos.toRange()), table => positionIn(last, editor.getBody()).filter(lastPos => lastPos.isEqual(pos)).fold(() => moveToRange(editor, pos.toRange()), _ => renderBlock(down, editor, table)));
  22060. };
  22061. const navigateVertically = (editor, down, table, td) => {
  22062. const rng = editor.selection.getRng();
  22063. const pos = CaretPosition.fromRangeStart(rng);
  22064. const root = editor.getBody();
  22065. if (!down && isAtFirstTableCellLine(td, pos)) {
  22066. const newPos = getClosestAbovePosition(root, table, pos);
  22067. moveCaret(editor, down, newPos);
  22068. return true;
  22069. } else if (down && isAtLastTableCellLine(td, pos)) {
  22070. const newPos = getClosestBelowPosition(root, table, pos);
  22071. moveCaret(editor, down, newPos);
  22072. return true;
  22073. } else {
  22074. return false;
  22075. }
  22076. };
  22077. const move$1 = (editor, forward, mover) => Optional.from(editor.dom.getParent(editor.selection.getNode(), 'td,th')).bind(td => Optional.from(editor.dom.getParent(td, 'table')).map(table => mover(editor, forward, table, td))).getOr(false);
  22078. const moveH = (editor, forward) => move$1(editor, forward, navigateHorizontally);
  22079. const moveV = (editor, forward) => move$1(editor, forward, navigateVertically);
  22080. const getCellFirstCursorPosition = cell => {
  22081. const selection = SimSelection.exact(cell, 0, cell, 0);
  22082. return toNative(selection);
  22083. };
  22084. const tabGo = (editor, isRoot, cell) => {
  22085. return cell.fold(Optional.none, Optional.none, (_current, next) => {
  22086. return first(next).map(cell => {
  22087. return getCellFirstCursorPosition(cell);
  22088. });
  22089. }, current => {
  22090. editor.execCommand('mceTableInsertRowAfter');
  22091. return tabForward(editor, isRoot, current);
  22092. });
  22093. };
  22094. const tabForward = (editor, isRoot, cell) => tabGo(editor, isRoot, next(cell, isEditable));
  22095. const tabBackward = (editor, isRoot, cell) => tabGo(editor, isRoot, prev(cell, isEditable));
  22096. const handleTab = (editor, forward) => {
  22097. const rootElements = [
  22098. 'table',
  22099. 'li',
  22100. 'dl'
  22101. ];
  22102. const body = SugarElement.fromDom(editor.getBody());
  22103. const isRoot = element => {
  22104. const name$1 = name(element);
  22105. return eq(element, body) || contains$2(rootElements, name$1);
  22106. };
  22107. const rng = editor.selection.getRng();
  22108. const container = SugarElement.fromDom(!forward ? rng.startContainer : rng.endContainer);
  22109. return cell(container, isRoot).map(cell => {
  22110. table(cell, isRoot).each(table => {
  22111. editor.model.table.clearSelectedCells(table.dom);
  22112. });
  22113. editor.selection.collapse(!forward);
  22114. const navigation = !forward ? tabBackward : tabForward;
  22115. const rng = navigation(editor, isRoot, cell);
  22116. rng.each(range => {
  22117. editor.selection.setRng(range);
  22118. });
  22119. return true;
  22120. }).getOr(false);
  22121. };
  22122. const executeKeydownOverride$4 = (editor, caret, evt) => {
  22123. const isMac = Env.os.isMacOS() || Env.os.isiOS();
  22124. execute([
  22125. {
  22126. keyCode: VK.RIGHT,
  22127. action: action(moveH$2, editor, true)
  22128. },
  22129. {
  22130. keyCode: VK.LEFT,
  22131. action: action(moveH$2, editor, false)
  22132. },
  22133. {
  22134. keyCode: VK.UP,
  22135. action: action(moveV$3, editor, false)
  22136. },
  22137. {
  22138. keyCode: VK.DOWN,
  22139. action: action(moveV$3, editor, true)
  22140. },
  22141. ...isMac ? [
  22142. {
  22143. keyCode: VK.UP,
  22144. action: action(selectToEndPoint, editor, false),
  22145. metaKey: true,
  22146. shiftKey: true
  22147. },
  22148. {
  22149. keyCode: VK.DOWN,
  22150. action: action(selectToEndPoint, editor, true),
  22151. metaKey: true,
  22152. shiftKey: true
  22153. }
  22154. ] : [],
  22155. {
  22156. keyCode: VK.RIGHT,
  22157. action: action(moveH, editor, true)
  22158. },
  22159. {
  22160. keyCode: VK.LEFT,
  22161. action: action(moveH, editor, false)
  22162. },
  22163. {
  22164. keyCode: VK.UP,
  22165. action: action(moveV, editor, false)
  22166. },
  22167. {
  22168. keyCode: VK.DOWN,
  22169. action: action(moveV, editor, true)
  22170. },
  22171. {
  22172. keyCode: VK.RIGHT,
  22173. action: action(moveH$1, editor, true)
  22174. },
  22175. {
  22176. keyCode: VK.LEFT,
  22177. action: action(moveH$1, editor, false)
  22178. },
  22179. {
  22180. keyCode: VK.UP,
  22181. action: action(moveV$1, editor, false)
  22182. },
  22183. {
  22184. keyCode: VK.DOWN,
  22185. action: action(moveV$1, editor, true)
  22186. },
  22187. {
  22188. keyCode: VK.RIGHT,
  22189. action: action(move$2, editor, caret, true)
  22190. },
  22191. {
  22192. keyCode: VK.LEFT,
  22193. action: action(move$2, editor, caret, false)
  22194. },
  22195. {
  22196. keyCode: VK.RIGHT,
  22197. ctrlKey: !isMac,
  22198. altKey: isMac,
  22199. action: action(moveNextWord, editor, caret)
  22200. },
  22201. {
  22202. keyCode: VK.LEFT,
  22203. ctrlKey: !isMac,
  22204. altKey: isMac,
  22205. action: action(movePrevWord, editor, caret)
  22206. },
  22207. {
  22208. keyCode: VK.UP,
  22209. action: action(moveV$2, editor, false)
  22210. },
  22211. {
  22212. keyCode: VK.DOWN,
  22213. action: action(moveV$2, editor, true)
  22214. }
  22215. ], evt).each(_ => {
  22216. evt.preventDefault();
  22217. });
  22218. };
  22219. const setup$k = (editor, caret) => {
  22220. editor.on('keydown', evt => {
  22221. if (!evt.isDefaultPrevented()) {
  22222. executeKeydownOverride$4(editor, caret, evt);
  22223. }
  22224. });
  22225. };
  22226. const point = (container, offset) => ({
  22227. container,
  22228. offset
  22229. });
  22230. const DOM$7 = DOMUtils.DOM;
  22231. const alwaysNext = startNode => node => startNode === node ? -1 : 0;
  22232. const isBoundary = dom => node => dom.isBlock(node) || contains$2([
  22233. 'BR',
  22234. 'IMG',
  22235. 'HR',
  22236. 'INPUT'
  22237. ], node.nodeName) || dom.getContentEditable(node) === 'false';
  22238. const textBefore = (node, offset, rootNode) => {
  22239. if (isText$a(node) && offset >= 0) {
  22240. return Optional.some(point(node, offset));
  22241. } else {
  22242. const textSeeker = TextSeeker(DOM$7);
  22243. return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, prev.container.data.length));
  22244. }
  22245. };
  22246. const textAfter = (node, offset, rootNode) => {
  22247. if (isText$a(node) && offset >= node.length) {
  22248. return Optional.some(point(node, offset));
  22249. } else {
  22250. const textSeeker = TextSeeker(DOM$7);
  22251. return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).map(prev => point(prev.container, 0));
  22252. }
  22253. };
  22254. const scanLeft = (node, offset, rootNode) => {
  22255. if (!isText$a(node)) {
  22256. return Optional.none();
  22257. }
  22258. const text = node.data;
  22259. if (offset >= 0 && offset <= text.length) {
  22260. return Optional.some(point(node, offset));
  22261. } else {
  22262. const textSeeker = TextSeeker(DOM$7);
  22263. return Optional.from(textSeeker.backwards(node, offset, alwaysNext(node), rootNode)).bind(prev => {
  22264. const prevText = prev.container.data;
  22265. return scanLeft(prev.container, offset + prevText.length, rootNode);
  22266. });
  22267. }
  22268. };
  22269. const scanRight = (node, offset, rootNode) => {
  22270. if (!isText$a(node)) {
  22271. return Optional.none();
  22272. }
  22273. const text = node.data;
  22274. if (offset <= text.length) {
  22275. return Optional.some(point(node, offset));
  22276. } else {
  22277. const textSeeker = TextSeeker(DOM$7);
  22278. return Optional.from(textSeeker.forwards(node, offset, alwaysNext(node), rootNode)).bind(next => scanRight(next.container, offset - text.length, rootNode));
  22279. }
  22280. };
  22281. const repeatLeft = (dom, node, offset, process, rootNode) => {
  22282. const search = TextSeeker(dom, isBoundary(dom));
  22283. return Optional.from(search.backwards(node, offset, process, rootNode));
  22284. };
  22285. const isValidTextRange = rng => rng.collapsed && isText$a(rng.startContainer);
  22286. const getText = rng => trim$1(rng.toString().replace(/\u00A0/g, ' '));
  22287. const isWhitespace = chr => chr !== '' && ' \xA0\f\n\r\t\x0B'.indexOf(chr) !== -1;
  22288. const stripTrigger = (text, trigger) => text.substring(trigger.length);
  22289. const findTrigger = (text, index, trigger) => {
  22290. let i;
  22291. const firstChar = trigger.charAt(0);
  22292. for (i = index - 1; i >= 0; i--) {
  22293. const char = text.charAt(i);
  22294. if (isWhitespace(char)) {
  22295. return Optional.none();
  22296. }
  22297. if (firstChar === char && contains$1(text, trigger, i, index)) {
  22298. break;
  22299. }
  22300. }
  22301. return Optional.some(i);
  22302. };
  22303. const findStart = (dom, initRange, trigger, minChars = 0) => {
  22304. if (!isValidTextRange(initRange)) {
  22305. return Optional.none();
  22306. }
  22307. const buffer = {
  22308. text: '',
  22309. offset: 0
  22310. };
  22311. const findTriggerIndex = (element, offset, text) => {
  22312. buffer.text = text + buffer.text;
  22313. buffer.offset += offset;
  22314. return findTrigger(buffer.text, buffer.offset, trigger).getOr(offset);
  22315. };
  22316. const root = dom.getParent(initRange.startContainer, dom.isBlock) || dom.getRoot();
  22317. return repeatLeft(dom, initRange.startContainer, initRange.startOffset, findTriggerIndex, root).bind(spot => {
  22318. const range = initRange.cloneRange();
  22319. range.setStart(spot.container, spot.offset);
  22320. range.setEnd(initRange.endContainer, initRange.endOffset);
  22321. if (range.collapsed) {
  22322. return Optional.none();
  22323. }
  22324. const text = getText(range);
  22325. const triggerIndex = text.lastIndexOf(trigger);
  22326. if (triggerIndex !== 0 || stripTrigger(text, trigger).length < minChars) {
  22327. return Optional.none();
  22328. } else {
  22329. return Optional.some({
  22330. text: stripTrigger(text, trigger),
  22331. range,
  22332. trigger
  22333. });
  22334. }
  22335. });
  22336. };
  22337. const getContext = (dom, initRange, trigger, minChars = 0) => detect$1(SugarElement.fromDom(initRange.startContainer)).fold(() => findStart(dom, initRange, trigger, minChars), elm => {
  22338. const range = dom.createRng();
  22339. range.selectNode(elm.dom);
  22340. const text = getText(range);
  22341. return Optional.some({
  22342. range,
  22343. text: stripTrigger(text, trigger),
  22344. trigger
  22345. });
  22346. });
  22347. const isText$1 = node => node.nodeType === TEXT;
  22348. const isElement = node => node.nodeType === ELEMENT;
  22349. const toLast = node => {
  22350. if (isText$1(node)) {
  22351. return point(node, node.data.length);
  22352. } else {
  22353. const children = node.childNodes;
  22354. return children.length > 0 ? toLast(children[children.length - 1]) : point(node, children.length);
  22355. }
  22356. };
  22357. const toLeaf = (node, offset) => {
  22358. const children = node.childNodes;
  22359. if (children.length > 0 && offset < children.length) {
  22360. return toLeaf(children[offset], 0);
  22361. } else if (children.length > 0 && isElement(node) && children.length === offset) {
  22362. return toLast(children[children.length - 1]);
  22363. } else {
  22364. return point(node, offset);
  22365. }
  22366. };
  22367. const isPreviousCharContent = (dom, leaf) => {
  22368. var _a;
  22369. const root = (_a = dom.getParent(leaf.container, dom.isBlock)) !== null && _a !== void 0 ? _a : dom.getRoot();
  22370. return repeatLeft(dom, leaf.container, leaf.offset, (_element, offset) => offset === 0 ? -1 : offset, root).filter(spot => {
  22371. const char = spot.container.data.charAt(spot.offset - 1);
  22372. return !isWhitespace(char);
  22373. }).isSome();
  22374. };
  22375. const isStartOfWord = dom => rng => {
  22376. const leaf = toLeaf(rng.startContainer, rng.startOffset);
  22377. return !isPreviousCharContent(dom, leaf);
  22378. };
  22379. const getTriggerContext = (dom, initRange, database) => findMap(database.triggers, trigger => getContext(dom, initRange, trigger));
  22380. const lookup = (editor, getDatabase) => {
  22381. const database = getDatabase();
  22382. const rng = editor.selection.getRng();
  22383. return getTriggerContext(editor.dom, rng, database).bind(context => lookupWithContext(editor, getDatabase, context));
  22384. };
  22385. const lookupWithContext = (editor, getDatabase, context, fetchOptions = {}) => {
  22386. var _a;
  22387. const database = getDatabase();
  22388. const rng = editor.selection.getRng();
  22389. const startText = (_a = rng.startContainer.nodeValue) !== null && _a !== void 0 ? _a : '';
  22390. const autocompleters = filter$5(database.lookupByTrigger(context.trigger), autocompleter => context.text.length >= autocompleter.minChars && autocompleter.matches.getOrThunk(() => isStartOfWord(editor.dom))(context.range, startText, context.text));
  22391. if (autocompleters.length === 0) {
  22392. return Optional.none();
  22393. }
  22394. const lookupData = Promise.all(map$3(autocompleters, ac => {
  22395. const fetchResult = ac.fetch(context.text, ac.maxResults, fetchOptions);
  22396. return fetchResult.then(results => ({
  22397. matchText: context.text,
  22398. items: results,
  22399. columns: ac.columns,
  22400. onAction: ac.onAction,
  22401. highlightOn: ac.highlightOn
  22402. }));
  22403. }));
  22404. return Optional.some({
  22405. lookupData,
  22406. context
  22407. });
  22408. };
  22409. var SimpleResultType;
  22410. (function (SimpleResultType) {
  22411. SimpleResultType[SimpleResultType['Error'] = 0] = 'Error';
  22412. SimpleResultType[SimpleResultType['Value'] = 1] = 'Value';
  22413. }(SimpleResultType || (SimpleResultType = {})));
  22414. const fold$1 = (res, onError, onValue) => res.stype === SimpleResultType.Error ? onError(res.serror) : onValue(res.svalue);
  22415. const partition = results => {
  22416. const values = [];
  22417. const errors = [];
  22418. each$e(results, obj => {
  22419. fold$1(obj, err => errors.push(err), val => values.push(val));
  22420. });
  22421. return {
  22422. values,
  22423. errors
  22424. };
  22425. };
  22426. const mapError = (res, f) => {
  22427. if (res.stype === SimpleResultType.Error) {
  22428. return {
  22429. stype: SimpleResultType.Error,
  22430. serror: f(res.serror)
  22431. };
  22432. } else {
  22433. return res;
  22434. }
  22435. };
  22436. const map = (res, f) => {
  22437. if (res.stype === SimpleResultType.Value) {
  22438. return {
  22439. stype: SimpleResultType.Value,
  22440. svalue: f(res.svalue)
  22441. };
  22442. } else {
  22443. return res;
  22444. }
  22445. };
  22446. const bind = (res, f) => {
  22447. if (res.stype === SimpleResultType.Value) {
  22448. return f(res.svalue);
  22449. } else {
  22450. return res;
  22451. }
  22452. };
  22453. const bindError = (res, f) => {
  22454. if (res.stype === SimpleResultType.Error) {
  22455. return f(res.serror);
  22456. } else {
  22457. return res;
  22458. }
  22459. };
  22460. const svalue = v => ({
  22461. stype: SimpleResultType.Value,
  22462. svalue: v
  22463. });
  22464. const serror = e => ({
  22465. stype: SimpleResultType.Error,
  22466. serror: e
  22467. });
  22468. const toResult = res => fold$1(res, Result.error, Result.value);
  22469. const fromResult = res => res.fold(serror, svalue);
  22470. const SimpleResult = {
  22471. fromResult,
  22472. toResult,
  22473. svalue,
  22474. partition,
  22475. serror,
  22476. bind,
  22477. bindError,
  22478. map,
  22479. mapError,
  22480. fold: fold$1
  22481. };
  22482. const formatObj = input => {
  22483. return isObject(input) && keys(input).length > 100 ? ' removed due to size' : JSON.stringify(input, null, 2);
  22484. };
  22485. const formatErrors = errors => {
  22486. const es = errors.length > 10 ? errors.slice(0, 10).concat([{
  22487. path: [],
  22488. getErrorInfo: constant('... (only showing first ten failures)')
  22489. }]) : errors;
  22490. return map$3(es, e => {
  22491. return 'Failed path: (' + e.path.join(' > ') + ')\n' + e.getErrorInfo();
  22492. });
  22493. };
  22494. const nu = (path, getErrorInfo) => {
  22495. return SimpleResult.serror([{
  22496. path,
  22497. getErrorInfo
  22498. }]);
  22499. };
  22500. const missingRequired = (path, key, obj) => nu(path, () => 'Could not find valid *required* value for "' + key + '" in ' + formatObj(obj));
  22501. const missingKey = (path, key) => nu(path, () => 'Choice schema did not contain choice key: "' + key + '"');
  22502. const missingBranch = (path, branches, branch) => nu(path, () => 'The chosen schema: "' + branch + '" did not exist in branches: ' + formatObj(branches));
  22503. const custom = (path, err) => nu(path, constant(err));
  22504. const chooseFrom = (path, input, branches, ch) => {
  22505. const fields = get$a(branches, ch);
  22506. return fields.fold(() => missingBranch(path, branches, ch), vp => vp.extract(path.concat(['branch: ' + ch]), input));
  22507. };
  22508. const choose$1 = (key, branches) => {
  22509. const extract = (path, input) => {
  22510. const choice = get$a(input, key);
  22511. return choice.fold(() => missingKey(path, key), chosen => chooseFrom(path, input, branches, chosen));
  22512. };
  22513. const toString = () => 'chooseOn(' + key + '). Possible values: ' + keys(branches);
  22514. return {
  22515. extract,
  22516. toString
  22517. };
  22518. };
  22519. const shallow = (old, nu) => {
  22520. return nu;
  22521. };
  22522. const deep = (old, nu) => {
  22523. const bothObjects = isPlainObject(old) && isPlainObject(nu);
  22524. return bothObjects ? deepMerge(old, nu) : nu;
  22525. };
  22526. const baseMerge = merger => {
  22527. return (...objects) => {
  22528. if (objects.length === 0) {
  22529. throw new Error(`Can't merge zero objects`);
  22530. }
  22531. const ret = {};
  22532. for (let j = 0; j < objects.length; j++) {
  22533. const curObject = objects[j];
  22534. for (const key in curObject) {
  22535. if (has$2(curObject, key)) {
  22536. ret[key] = merger(ret[key], curObject[key]);
  22537. }
  22538. }
  22539. }
  22540. return ret;
  22541. };
  22542. };
  22543. const deepMerge = baseMerge(deep);
  22544. const merge = baseMerge(shallow);
  22545. const required = () => ({
  22546. tag: 'required',
  22547. process: {}
  22548. });
  22549. const defaultedThunk = fallbackThunk => ({
  22550. tag: 'defaultedThunk',
  22551. process: fallbackThunk
  22552. });
  22553. const defaulted$1 = fallback => defaultedThunk(constant(fallback));
  22554. const asOption = () => ({
  22555. tag: 'option',
  22556. process: {}
  22557. });
  22558. const mergeValues = (values, base) => values.length > 0 ? SimpleResult.svalue(deepMerge(base, merge.apply(undefined, values))) : SimpleResult.svalue(base);
  22559. const mergeErrors = errors => compose(SimpleResult.serror, flatten)(errors);
  22560. const consolidateObj = (objects, base) => {
  22561. const partition = SimpleResult.partition(objects);
  22562. return partition.errors.length > 0 ? mergeErrors(partition.errors) : mergeValues(partition.values, base);
  22563. };
  22564. const consolidateArr = objects => {
  22565. const partitions = SimpleResult.partition(objects);
  22566. return partitions.errors.length > 0 ? mergeErrors(partitions.errors) : SimpleResult.svalue(partitions.values);
  22567. };
  22568. const ResultCombine = {
  22569. consolidateObj,
  22570. consolidateArr
  22571. };
  22572. const field$1 = (key, newKey, presence, prop) => ({
  22573. tag: 'field',
  22574. key,
  22575. newKey,
  22576. presence,
  22577. prop
  22578. });
  22579. const customField$1 = (newKey, instantiator) => ({
  22580. tag: 'custom',
  22581. newKey,
  22582. instantiator
  22583. });
  22584. const fold = (value, ifField, ifCustom) => {
  22585. switch (value.tag) {
  22586. case 'field':
  22587. return ifField(value.key, value.newKey, value.presence, value.prop);
  22588. case 'custom':
  22589. return ifCustom(value.newKey, value.instantiator);
  22590. }
  22591. };
  22592. const value = validator => {
  22593. const extract = (path, val) => {
  22594. return SimpleResult.bindError(validator(val), err => custom(path, err));
  22595. };
  22596. const toString = constant('val');
  22597. return {
  22598. extract,
  22599. toString
  22600. };
  22601. };
  22602. const anyValue$1 = value(SimpleResult.svalue);
  22603. const requiredAccess = (path, obj, key, bundle) => get$a(obj, key).fold(() => missingRequired(path, key, obj), bundle);
  22604. const fallbackAccess = (obj, key, fallback, bundle) => {
  22605. const v = get$a(obj, key).getOrThunk(() => fallback(obj));
  22606. return bundle(v);
  22607. };
  22608. const optionAccess = (obj, key, bundle) => bundle(get$a(obj, key));
  22609. const optionDefaultedAccess = (obj, key, fallback, bundle) => {
  22610. const opt = get$a(obj, key).map(val => val === true ? fallback(obj) : val);
  22611. return bundle(opt);
  22612. };
  22613. const extractField = (field, path, obj, key, prop) => {
  22614. const bundle = av => prop.extract(path.concat([key]), av);
  22615. const bundleAsOption = optValue => optValue.fold(() => SimpleResult.svalue(Optional.none()), ov => {
  22616. const result = prop.extract(path.concat([key]), ov);
  22617. return SimpleResult.map(result, Optional.some);
  22618. });
  22619. switch (field.tag) {
  22620. case 'required':
  22621. return requiredAccess(path, obj, key, bundle);
  22622. case 'defaultedThunk':
  22623. return fallbackAccess(obj, key, field.process, bundle);
  22624. case 'option':
  22625. return optionAccess(obj, key, bundleAsOption);
  22626. case 'defaultedOptionThunk':
  22627. return optionDefaultedAccess(obj, key, field.process, bundleAsOption);
  22628. case 'mergeWithThunk': {
  22629. return fallbackAccess(obj, key, constant({}), v => {
  22630. const result = deepMerge(field.process(obj), v);
  22631. return bundle(result);
  22632. });
  22633. }
  22634. }
  22635. };
  22636. const extractFields = (path, obj, fields) => {
  22637. const success = {};
  22638. const errors = [];
  22639. for (const field of fields) {
  22640. fold(field, (key, newKey, presence, prop) => {
  22641. const result = extractField(presence, path, obj, key, prop);
  22642. SimpleResult.fold(result, err => {
  22643. errors.push(...err);
  22644. }, res => {
  22645. success[newKey] = res;
  22646. });
  22647. }, (newKey, instantiator) => {
  22648. success[newKey] = instantiator(obj);
  22649. });
  22650. }
  22651. return errors.length > 0 ? SimpleResult.serror(errors) : SimpleResult.svalue(success);
  22652. };
  22653. const objOf = values => {
  22654. const extract = (path, o) => extractFields(path, o, values);
  22655. const toString = () => {
  22656. const fieldStrings = map$3(values, value => fold(value, (key, _okey, _presence, prop) => key + ' -> ' + prop.toString(), (newKey, _instantiator) => 'state(' + newKey + ')'));
  22657. return 'obj{\n' + fieldStrings.join('\n') + '}';
  22658. };
  22659. return {
  22660. extract,
  22661. toString
  22662. };
  22663. };
  22664. const arrOf = prop => {
  22665. const extract = (path, array) => {
  22666. const results = map$3(array, (a, i) => prop.extract(path.concat(['[' + i + ']']), a));
  22667. return ResultCombine.consolidateArr(results);
  22668. };
  22669. const toString = () => 'array(' + prop.toString() + ')';
  22670. return {
  22671. extract,
  22672. toString
  22673. };
  22674. };
  22675. const valueOf = validator => value(v => validator(v).fold(SimpleResult.serror, SimpleResult.svalue));
  22676. const extractValue = (label, prop, obj) => {
  22677. const res = prop.extract([label], obj);
  22678. return SimpleResult.mapError(res, errs => ({
  22679. input: obj,
  22680. errors: errs
  22681. }));
  22682. };
  22683. const asRaw = (label, prop, obj) => SimpleResult.toResult(extractValue(label, prop, obj));
  22684. const formatError = errInfo => {
  22685. return 'Errors: \n' + formatErrors(errInfo.errors).join('\n') + '\n\nInput object: ' + formatObj(errInfo.input);
  22686. };
  22687. const choose = (key, branches) => choose$1(key, map$2(branches, objOf));
  22688. const anyValue = constant(anyValue$1);
  22689. const typedValue = (validator, expectedType) => value(a => {
  22690. const actualType = typeof a;
  22691. return validator(a) ? SimpleResult.svalue(a) : SimpleResult.serror(`Expected type: ${ expectedType } but got: ${ actualType }`);
  22692. });
  22693. const number = typedValue(isNumber, 'number');
  22694. const string = typedValue(isString, 'string');
  22695. const boolean = typedValue(isBoolean, 'boolean');
  22696. const functionProcessor = typedValue(isFunction, 'function');
  22697. const field = field$1;
  22698. const customField = customField$1;
  22699. const validateEnum = values => valueOf(value => contains$2(values, value) ? Result.value(value) : Result.error(`Unsupported value: "${ value }", choose one of "${ values.join(', ') }".`));
  22700. const requiredOf = (key, schema) => field(key, key, required(), schema);
  22701. const requiredString = key => requiredOf(key, string);
  22702. const requiredFunction = key => requiredOf(key, functionProcessor);
  22703. const requiredArrayOf = (key, schema) => field(key, key, required(), arrOf(schema));
  22704. const optionOf = (key, schema) => field(key, key, asOption(), schema);
  22705. const optionString = key => optionOf(key, string);
  22706. const optionFunction = key => optionOf(key, functionProcessor);
  22707. const defaulted = (key, fallback) => field(key, key, defaulted$1(fallback), anyValue());
  22708. const defaultedOf = (key, fallback, schema) => field(key, key, defaulted$1(fallback), schema);
  22709. const defaultedNumber = (key, fallback) => defaultedOf(key, fallback, number);
  22710. const defaultedString = (key, fallback) => defaultedOf(key, fallback, string);
  22711. const defaultedStringEnum = (key, fallback, values) => defaultedOf(key, fallback, validateEnum(values));
  22712. const defaultedBoolean = (key, fallback) => defaultedOf(key, fallback, boolean);
  22713. const defaultedFunction = (key, fallback) => defaultedOf(key, fallback, functionProcessor);
  22714. const defaultedArrayOf = (key, fallback, schema) => defaultedOf(key, fallback, arrOf(schema));
  22715. const type = requiredString('type');
  22716. const fetch$1 = requiredFunction('fetch');
  22717. const onAction = requiredFunction('onAction');
  22718. const onSetup = defaultedFunction('onSetup', () => noop);
  22719. const optionalText = optionString('text');
  22720. const optionalIcon = optionString('icon');
  22721. const optionalTooltip = optionString('tooltip');
  22722. const optionalLabel = optionString('label');
  22723. const active = defaultedBoolean('active', false);
  22724. const enabled = defaultedBoolean('enabled', true);
  22725. const primary = defaultedBoolean('primary', false);
  22726. const defaultedColumns = num => defaulted('columns', num);
  22727. const defaultedType = type => defaultedString('type', type);
  22728. const autocompleterSchema = objOf([
  22729. type,
  22730. requiredString('trigger'),
  22731. defaultedNumber('minChars', 1),
  22732. defaultedColumns(1),
  22733. defaultedNumber('maxResults', 10),
  22734. optionFunction('matches'),
  22735. fetch$1,
  22736. onAction,
  22737. defaultedArrayOf('highlightOn', [], string)
  22738. ]);
  22739. const createAutocompleter = spec => asRaw('Autocompleter', autocompleterSchema, {
  22740. trigger: spec.ch,
  22741. ...spec
  22742. });
  22743. const baseToolbarButtonFields = [
  22744. enabled,
  22745. optionalTooltip,
  22746. optionalIcon,
  22747. optionalText,
  22748. onSetup
  22749. ];
  22750. const baseToolbarToggleButtonFields = [active].concat(baseToolbarButtonFields);
  22751. const contextBarFields = [
  22752. defaultedFunction('predicate', never),
  22753. defaultedStringEnum('scope', 'node', [
  22754. 'node',
  22755. 'editor'
  22756. ]),
  22757. defaultedStringEnum('position', 'selection', [
  22758. 'node',
  22759. 'selection',
  22760. 'line'
  22761. ])
  22762. ];
  22763. const contextButtonFields = baseToolbarButtonFields.concat([
  22764. defaultedType('contextformbutton'),
  22765. primary,
  22766. onAction,
  22767. customField('original', identity)
  22768. ]);
  22769. const contextToggleButtonFields = baseToolbarToggleButtonFields.concat([
  22770. defaultedType('contextformbutton'),
  22771. primary,
  22772. onAction,
  22773. customField('original', identity)
  22774. ]);
  22775. const launchButtonFields = baseToolbarButtonFields.concat([defaultedType('contextformbutton')]);
  22776. const launchToggleButtonFields = baseToolbarToggleButtonFields.concat([defaultedType('contextformtogglebutton')]);
  22777. const toggleOrNormal = choose('type', {
  22778. contextformbutton: contextButtonFields,
  22779. contextformtogglebutton: contextToggleButtonFields
  22780. });
  22781. objOf([
  22782. defaultedType('contextform'),
  22783. defaultedFunction('initValue', constant('')),
  22784. optionalLabel,
  22785. requiredArrayOf('commands', toggleOrNormal),
  22786. optionOf('launch', choose('type', {
  22787. contextformbutton: launchButtonFields,
  22788. contextformtogglebutton: launchToggleButtonFields
  22789. }))
  22790. ].concat(contextBarFields));
  22791. const register$2 = editor => {
  22792. const popups = editor.ui.registry.getAll().popups;
  22793. const dataset = map$2(popups, popup => createAutocompleter(popup).fold(err => {
  22794. throw new Error(formatError(err));
  22795. }, identity));
  22796. const triggers = stringArray(mapToArray(dataset, v => v.trigger));
  22797. const datasetValues = values(dataset);
  22798. const lookupByTrigger = trigger => filter$5(datasetValues, dv => dv.trigger === trigger);
  22799. return {
  22800. dataset,
  22801. triggers,
  22802. lookupByTrigger
  22803. };
  22804. };
  22805. const setupEditorInput = (editor, api) => {
  22806. const update = last$1(api.load, 50);
  22807. editor.on('keypress compositionend', e => {
  22808. if (e.which === 27) {
  22809. return;
  22810. }
  22811. update.throttle();
  22812. });
  22813. editor.on('keydown', e => {
  22814. const keyCode = e.which;
  22815. if (keyCode === 8) {
  22816. update.throttle();
  22817. } else if (keyCode === 27) {
  22818. api.cancelIfNecessary();
  22819. }
  22820. });
  22821. editor.on('remove', update.cancel);
  22822. };
  22823. const setup$j = editor => {
  22824. const activeAutocompleter = value$2();
  22825. const uiActive = Cell(false);
  22826. const isActive = activeAutocompleter.isSet;
  22827. const cancelIfNecessary = () => {
  22828. if (isActive()) {
  22829. removeAutocompleterDecoration(editor);
  22830. fireAutocompleterEnd(editor);
  22831. uiActive.set(false);
  22832. activeAutocompleter.clear();
  22833. }
  22834. };
  22835. const commenceIfNecessary = context => {
  22836. if (!isActive()) {
  22837. addAutocompleterDecoration(editor, context.range);
  22838. activeAutocompleter.set({
  22839. trigger: context.trigger,
  22840. matchLength: context.text.length
  22841. });
  22842. }
  22843. };
  22844. const getAutocompleters = cached(() => register$2(editor));
  22845. const doLookup = fetchOptions => activeAutocompleter.get().map(ac => getContext(editor.dom, editor.selection.getRng(), ac.trigger).bind(newContext => lookupWithContext(editor, getAutocompleters, newContext, fetchOptions))).getOrThunk(() => lookup(editor, getAutocompleters));
  22846. const load = fetchOptions => {
  22847. doLookup(fetchOptions).fold(cancelIfNecessary, lookupInfo => {
  22848. commenceIfNecessary(lookupInfo.context);
  22849. lookupInfo.lookupData.then(lookupData => {
  22850. activeAutocompleter.get().map(ac => {
  22851. const context = lookupInfo.context;
  22852. if (ac.trigger === context.trigger) {
  22853. if (context.text.length - ac.matchLength >= 10) {
  22854. cancelIfNecessary();
  22855. } else {
  22856. activeAutocompleter.set({
  22857. ...ac,
  22858. matchLength: context.text.length
  22859. });
  22860. if (uiActive.get()) {
  22861. fireAutocompleterUpdate(editor, { lookupData });
  22862. } else {
  22863. uiActive.set(true);
  22864. fireAutocompleterStart(editor, { lookupData });
  22865. }
  22866. }
  22867. }
  22868. });
  22869. });
  22870. });
  22871. };
  22872. editor.addCommand('mceAutocompleterReload', (_ui, value) => {
  22873. const fetchOptions = isObject(value) ? value.fetchOptions : {};
  22874. load(fetchOptions);
  22875. });
  22876. editor.addCommand('mceAutocompleterClose', cancelIfNecessary);
  22877. setupEditorInput(editor, {
  22878. cancelIfNecessary,
  22879. load
  22880. });
  22881. };
  22882. const createAndFireInputEvent = eventType => (editor, inputType, specifics = {}) => {
  22883. const target = editor.getBody();
  22884. const overrides = {
  22885. bubbles: true,
  22886. composed: true,
  22887. data: null,
  22888. isComposing: false,
  22889. detail: 0,
  22890. view: null,
  22891. target,
  22892. currentTarget: target,
  22893. eventPhase: Event.AT_TARGET,
  22894. originalTarget: target,
  22895. explicitOriginalTarget: target,
  22896. isTrusted: false,
  22897. srcElement: target,
  22898. cancelable: false,
  22899. preventDefault: noop,
  22900. inputType
  22901. };
  22902. const input = clone$3(new InputEvent(eventType));
  22903. return editor.dispatch(eventType, {
  22904. ...input,
  22905. ...overrides,
  22906. ...specifics
  22907. });
  22908. };
  22909. const fireFakeInputEvent = createAndFireInputEvent('input');
  22910. const fireFakeBeforeInputEvent = createAndFireInputEvent('beforeinput');
  22911. const executeKeydownOverride$3 = (editor, caret, evt) => {
  22912. const inputType = evt.keyCode === VK.BACKSPACE ? 'deleteContentBackward' : 'deleteContentForward';
  22913. executeWithDelayedAction([
  22914. {
  22915. keyCode: VK.BACKSPACE,
  22916. action: action(backspaceDelete, editor)
  22917. },
  22918. {
  22919. keyCode: VK.BACKSPACE,
  22920. action: action(backspaceDelete$5, editor, false)
  22921. },
  22922. {
  22923. keyCode: VK.DELETE,
  22924. action: action(backspaceDelete$5, editor, true)
  22925. },
  22926. {
  22927. keyCode: VK.BACKSPACE,
  22928. action: action(backspaceDelete$6, editor, false)
  22929. },
  22930. {
  22931. keyCode: VK.DELETE,
  22932. action: action(backspaceDelete$6, editor, true)
  22933. },
  22934. {
  22935. keyCode: VK.BACKSPACE,
  22936. action: action(backspaceDelete$3, editor, caret, false)
  22937. },
  22938. {
  22939. keyCode: VK.DELETE,
  22940. action: action(backspaceDelete$3, editor, caret, true)
  22941. },
  22942. {
  22943. keyCode: VK.BACKSPACE,
  22944. action: action(backspaceDelete$9, editor, false)
  22945. },
  22946. {
  22947. keyCode: VK.DELETE,
  22948. action: action(backspaceDelete$9, editor, true)
  22949. },
  22950. {
  22951. keyCode: VK.BACKSPACE,
  22952. action: action(backspaceDelete$4, editor, false)
  22953. },
  22954. {
  22955. keyCode: VK.DELETE,
  22956. action: action(backspaceDelete$4, editor, true)
  22957. },
  22958. {
  22959. keyCode: VK.BACKSPACE,
  22960. action: action(backspaceDelete$1, editor, false)
  22961. },
  22962. {
  22963. keyCode: VK.DELETE,
  22964. action: action(backspaceDelete$1, editor, true)
  22965. },
  22966. {
  22967. keyCode: VK.BACKSPACE,
  22968. action: action(backspaceDelete$7, editor, false)
  22969. },
  22970. {
  22971. keyCode: VK.DELETE,
  22972. action: action(backspaceDelete$7, editor, true)
  22973. },
  22974. {
  22975. keyCode: VK.BACKSPACE,
  22976. action: action(backspaceDelete$8, editor, false)
  22977. },
  22978. {
  22979. keyCode: VK.DELETE,
  22980. action: action(backspaceDelete$8, editor, true)
  22981. },
  22982. {
  22983. keyCode: VK.BACKSPACE,
  22984. action: action(backspaceDelete$2, editor, false)
  22985. },
  22986. {
  22987. keyCode: VK.DELETE,
  22988. action: action(backspaceDelete$2, editor, true)
  22989. }
  22990. ], evt).each(applyAction => {
  22991. evt.preventDefault();
  22992. const beforeInput = fireFakeBeforeInputEvent(editor, inputType);
  22993. if (!beforeInput.isDefaultPrevented()) {
  22994. applyAction();
  22995. fireFakeInputEvent(editor, inputType);
  22996. }
  22997. });
  22998. };
  22999. const executeKeyupOverride = (editor, evt) => {
  23000. execute([
  23001. {
  23002. keyCode: VK.BACKSPACE,
  23003. action: action(paddEmptyElement, editor)
  23004. },
  23005. {
  23006. keyCode: VK.DELETE,
  23007. action: action(paddEmptyElement, editor)
  23008. }
  23009. ], evt);
  23010. };
  23011. const setup$i = (editor, caret) => {
  23012. editor.on('keydown', evt => {
  23013. if (!evt.isDefaultPrevented()) {
  23014. executeKeydownOverride$3(editor, caret, evt);
  23015. }
  23016. });
  23017. editor.on('keyup', evt => {
  23018. if (!evt.isDefaultPrevented()) {
  23019. executeKeyupOverride(editor, evt);
  23020. }
  23021. });
  23022. };
  23023. const firstNonWhiteSpaceNodeSibling = node => {
  23024. while (node) {
  23025. if (isElement$6(node) || isText$a(node) && node.data && /[\r\n\s]/.test(node.data)) {
  23026. return node;
  23027. }
  23028. node = node.nextSibling;
  23029. }
  23030. return null;
  23031. };
  23032. const moveToCaretPosition = (editor, root) => {
  23033. const dom = editor.dom;
  23034. const moveCaretBeforeOnEnterElementsMap = editor.schema.getMoveCaretBeforeOnEnterElements();
  23035. if (!root) {
  23036. return;
  23037. }
  23038. if (/^(LI|DT|DD)$/.test(root.nodeName)) {
  23039. const firstChild = firstNonWhiteSpaceNodeSibling(root.firstChild);
  23040. if (firstChild && /^(UL|OL|DL)$/.test(firstChild.nodeName)) {
  23041. root.insertBefore(dom.doc.createTextNode(nbsp), root.firstChild);
  23042. }
  23043. }
  23044. const rng = dom.createRng();
  23045. root.normalize();
  23046. if (root.hasChildNodes()) {
  23047. const walker = new DomTreeWalker(root, root);
  23048. let lastNode = root;
  23049. let node;
  23050. while (node = walker.current()) {
  23051. if (isText$a(node)) {
  23052. rng.setStart(node, 0);
  23053. rng.setEnd(node, 0);
  23054. break;
  23055. }
  23056. if (moveCaretBeforeOnEnterElementsMap[node.nodeName.toLowerCase()]) {
  23057. rng.setStartBefore(node);
  23058. rng.setEndBefore(node);
  23059. break;
  23060. }
  23061. lastNode = node;
  23062. node = walker.next();
  23063. }
  23064. if (!node) {
  23065. rng.setStart(lastNode, 0);
  23066. rng.setEnd(lastNode, 0);
  23067. }
  23068. } else {
  23069. if (isBr$6(root)) {
  23070. if (root.nextSibling && dom.isBlock(root.nextSibling)) {
  23071. rng.setStartBefore(root);
  23072. rng.setEndBefore(root);
  23073. } else {
  23074. rng.setStartAfter(root);
  23075. rng.setEndAfter(root);
  23076. }
  23077. } else {
  23078. rng.setStart(root, 0);
  23079. rng.setEnd(root, 0);
  23080. }
  23081. }
  23082. editor.selection.setRng(rng);
  23083. scrollRangeIntoView(editor, rng);
  23084. };
  23085. const getEditableRoot = (dom, node) => {
  23086. const root = dom.getRoot();
  23087. let editableRoot;
  23088. let parent = node;
  23089. while (parent !== root && parent && dom.getContentEditable(parent) !== 'false') {
  23090. if (dom.getContentEditable(parent) === 'true') {
  23091. editableRoot = parent;
  23092. }
  23093. parent = parent.parentNode;
  23094. }
  23095. return parent !== root ? editableRoot : root;
  23096. };
  23097. const getParentBlock$1 = editor => {
  23098. return Optional.from(editor.dom.getParent(editor.selection.getStart(true), editor.dom.isBlock));
  23099. };
  23100. const getParentBlockName = editor => {
  23101. return getParentBlock$1(editor).fold(constant(''), parentBlock => {
  23102. return parentBlock.nodeName.toUpperCase();
  23103. });
  23104. };
  23105. const isListItemParentBlock = editor => {
  23106. return getParentBlock$1(editor).filter(elm => {
  23107. return isListItem$1(SugarElement.fromDom(elm));
  23108. }).isSome();
  23109. };
  23110. const hasFirstChild = (elm, name) => {
  23111. return elm.firstChild && elm.firstChild.nodeName === name;
  23112. };
  23113. const isFirstChild = elm => {
  23114. var _a;
  23115. return ((_a = elm.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === elm;
  23116. };
  23117. const hasParent = (elm, parentName) => {
  23118. const parentNode = elm === null || elm === void 0 ? void 0 : elm.parentNode;
  23119. return isNonNullable(parentNode) && parentNode.nodeName === parentName;
  23120. };
  23121. const isListBlock = elm => {
  23122. return isNonNullable(elm) && /^(OL|UL|LI)$/.test(elm.nodeName);
  23123. };
  23124. const isListItem = elm => {
  23125. return isNonNullable(elm) && /^(LI|DT|DD)$/.test(elm.nodeName);
  23126. };
  23127. const isNestedList = elm => {
  23128. return isListBlock(elm) && isListBlock(elm.parentNode);
  23129. };
  23130. const getContainerBlock = containerBlock => {
  23131. const containerBlockParent = containerBlock.parentNode;
  23132. return isListItem(containerBlockParent) ? containerBlockParent : containerBlock;
  23133. };
  23134. const isFirstOrLastLi = (containerBlock, parentBlock, first) => {
  23135. let node = containerBlock[first ? 'firstChild' : 'lastChild'];
  23136. while (node) {
  23137. if (isElement$6(node)) {
  23138. break;
  23139. }
  23140. node = node[first ? 'nextSibling' : 'previousSibling'];
  23141. }
  23142. return node === parentBlock;
  23143. };
  23144. const insert$3 = (editor, createNewBlock, containerBlock, parentBlock, newBlockName) => {
  23145. const dom = editor.dom;
  23146. const rng = editor.selection.getRng();
  23147. const containerParent = containerBlock.parentNode;
  23148. if (containerBlock === editor.getBody() || !containerParent) {
  23149. return;
  23150. }
  23151. if (isNestedList(containerBlock)) {
  23152. newBlockName = 'LI';
  23153. }
  23154. let newBlock = createNewBlock(newBlockName);
  23155. if (isFirstOrLastLi(containerBlock, parentBlock, true) && isFirstOrLastLi(containerBlock, parentBlock, false)) {
  23156. if (hasParent(containerBlock, 'LI')) {
  23157. const containerBlockParent = getContainerBlock(containerBlock);
  23158. dom.insertAfter(newBlock, containerBlockParent);
  23159. if (isFirstChild(containerBlock)) {
  23160. dom.remove(containerBlockParent);
  23161. } else {
  23162. dom.remove(containerBlock);
  23163. }
  23164. } else {
  23165. dom.replace(newBlock, containerBlock);
  23166. }
  23167. } else if (isFirstOrLastLi(containerBlock, parentBlock, true)) {
  23168. if (hasParent(containerBlock, 'LI')) {
  23169. dom.insertAfter(newBlock, getContainerBlock(containerBlock));
  23170. newBlock.appendChild(dom.doc.createTextNode(' '));
  23171. newBlock.appendChild(containerBlock);
  23172. } else {
  23173. containerParent.insertBefore(newBlock, containerBlock);
  23174. }
  23175. dom.remove(parentBlock);
  23176. } else if (isFirstOrLastLi(containerBlock, parentBlock, false)) {
  23177. dom.insertAfter(newBlock, getContainerBlock(containerBlock));
  23178. dom.remove(parentBlock);
  23179. } else {
  23180. containerBlock = getContainerBlock(containerBlock);
  23181. const tmpRng = rng.cloneRange();
  23182. tmpRng.setStartAfter(parentBlock);
  23183. tmpRng.setEndAfter(containerBlock);
  23184. const fragment = tmpRng.extractContents();
  23185. if (newBlockName === 'LI' && hasFirstChild(fragment, 'LI')) {
  23186. newBlock = fragment.firstChild;
  23187. dom.insertAfter(fragment, containerBlock);
  23188. } else {
  23189. dom.insertAfter(fragment, containerBlock);
  23190. dom.insertAfter(newBlock, containerBlock);
  23191. }
  23192. dom.remove(parentBlock);
  23193. }
  23194. moveToCaretPosition(editor, newBlock);
  23195. };
  23196. const trimZwsp = fragment => {
  23197. each$e(descendants$1(SugarElement.fromDom(fragment), isText$b), text => {
  23198. const rawNode = text.dom;
  23199. rawNode.nodeValue = trim$1(rawNode.data);
  23200. });
  23201. };
  23202. const isWithinNonEditableList = (editor, node) => {
  23203. const parentList = editor.dom.getParent(node, 'ol,ul,dl');
  23204. return parentList !== null && editor.dom.getContentEditableParent(parentList) === 'false';
  23205. };
  23206. const isEmptyAnchor = (dom, elm) => {
  23207. return elm && elm.nodeName === 'A' && dom.isEmpty(elm);
  23208. };
  23209. const emptyBlock = elm => {
  23210. elm.innerHTML = '<br data-mce-bogus="1">';
  23211. };
  23212. const containerAndSiblingName = (container, nodeName) => {
  23213. return container.nodeName === nodeName || container.previousSibling && container.previousSibling.nodeName === nodeName;
  23214. };
  23215. const canSplitBlock = (dom, node) => {
  23216. return isNonNullable(node) && dom.isBlock(node) && !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) && !/^(fixed|absolute)/i.test(node.style.position) && dom.getContentEditable(node) !== 'true';
  23217. };
  23218. const trimInlineElementsOnLeftSideOfBlock = (dom, nonEmptyElementsMap, block) => {
  23219. var _a;
  23220. const firstChilds = [];
  23221. if (!block) {
  23222. return;
  23223. }
  23224. let currentNode = block;
  23225. while (currentNode = currentNode.firstChild) {
  23226. if (dom.isBlock(currentNode)) {
  23227. return;
  23228. }
  23229. if (isElement$6(currentNode) && !nonEmptyElementsMap[currentNode.nodeName.toLowerCase()]) {
  23230. firstChilds.push(currentNode);
  23231. }
  23232. }
  23233. let i = firstChilds.length;
  23234. while (i--) {
  23235. currentNode = firstChilds[i];
  23236. if (!currentNode.hasChildNodes() || currentNode.firstChild === currentNode.lastChild && ((_a = currentNode.firstChild) === null || _a === void 0 ? void 0 : _a.nodeValue) === '') {
  23237. dom.remove(currentNode);
  23238. } else {
  23239. if (isEmptyAnchor(dom, currentNode)) {
  23240. dom.remove(currentNode);
  23241. }
  23242. }
  23243. }
  23244. };
  23245. const normalizeZwspOffset = (start, container, offset) => {
  23246. if (!isText$a(container)) {
  23247. return offset;
  23248. } else if (start) {
  23249. return offset === 1 && container.data.charAt(offset - 1) === ZWSP$1 ? 0 : offset;
  23250. } else {
  23251. return offset === container.data.length - 1 && container.data.charAt(offset) === ZWSP$1 ? container.data.length : offset;
  23252. }
  23253. };
  23254. const includeZwspInRange = rng => {
  23255. const newRng = rng.cloneRange();
  23256. newRng.setStart(rng.startContainer, normalizeZwspOffset(true, rng.startContainer, rng.startOffset));
  23257. newRng.setEnd(rng.endContainer, normalizeZwspOffset(false, rng.endContainer, rng.endOffset));
  23258. return newRng;
  23259. };
  23260. const trimLeadingLineBreaks = node => {
  23261. let currentNode = node;
  23262. do {
  23263. if (isText$a(currentNode)) {
  23264. currentNode.data = currentNode.data.replace(/^[\r\n]+/, '');
  23265. }
  23266. currentNode = currentNode.firstChild;
  23267. } while (currentNode);
  23268. };
  23269. const applyAttributes = (editor, node, forcedRootBlockAttrs) => {
  23270. const dom = editor.dom;
  23271. Optional.from(forcedRootBlockAttrs.style).map(dom.parseStyle).each(attrStyles => {
  23272. const currentStyles = getAllRaw(SugarElement.fromDom(node));
  23273. const newStyles = {
  23274. ...currentStyles,
  23275. ...attrStyles
  23276. };
  23277. dom.setStyles(node, newStyles);
  23278. });
  23279. const attrClassesOpt = Optional.from(forcedRootBlockAttrs.class).map(attrClasses => attrClasses.split(/\s+/));
  23280. const currentClassesOpt = Optional.from(node.className).map(currentClasses => filter$5(currentClasses.split(/\s+/), clazz => clazz !== ''));
  23281. lift2(attrClassesOpt, currentClassesOpt, (attrClasses, currentClasses) => {
  23282. const filteredClasses = filter$5(currentClasses, clazz => !contains$2(attrClasses, clazz));
  23283. const newClasses = [
  23284. ...attrClasses,
  23285. ...filteredClasses
  23286. ];
  23287. dom.setAttrib(node, 'class', newClasses.join(' '));
  23288. });
  23289. const appliedAttrs = [
  23290. 'style',
  23291. 'class'
  23292. ];
  23293. const remainingAttrs = filter$4(forcedRootBlockAttrs, (_, attrs) => !contains$2(appliedAttrs, attrs));
  23294. dom.setAttribs(node, remainingAttrs);
  23295. };
  23296. const setForcedBlockAttrs = (editor, node) => {
  23297. const forcedRootBlockName = getForcedRootBlock(editor);
  23298. if (forcedRootBlockName.toLowerCase() === node.tagName.toLowerCase()) {
  23299. const forcedRootBlockAttrs = getForcedRootBlockAttrs(editor);
  23300. applyAttributes(editor, node, forcedRootBlockAttrs);
  23301. }
  23302. };
  23303. const wrapSelfAndSiblingsInDefaultBlock = (editor, newBlockName, rng, container, offset) => {
  23304. var _a;
  23305. const dom = editor.dom;
  23306. const editableRoot = (_a = getEditableRoot(dom, container)) !== null && _a !== void 0 ? _a : dom.getRoot();
  23307. let parentBlock = dom.getParent(container, dom.isBlock);
  23308. if (!parentBlock || !canSplitBlock(dom, parentBlock)) {
  23309. parentBlock = parentBlock || editableRoot;
  23310. let rootBlockName;
  23311. if (parentBlock === editor.getBody() || isTableCellOrCaption(parentBlock)) {
  23312. rootBlockName = parentBlock.nodeName.toLowerCase();
  23313. } else if (parentBlock.parentNode) {
  23314. rootBlockName = parentBlock.parentNode.nodeName.toLowerCase();
  23315. } else {
  23316. rootBlockName = '';
  23317. }
  23318. if (!parentBlock.hasChildNodes()) {
  23319. const newBlock = dom.create(newBlockName);
  23320. setForcedBlockAttrs(editor, newBlock);
  23321. parentBlock.appendChild(newBlock);
  23322. rng.setStart(newBlock, 0);
  23323. rng.setEnd(newBlock, 0);
  23324. return newBlock;
  23325. }
  23326. let node = container;
  23327. while (node && node.parentNode !== parentBlock) {
  23328. node = node.parentNode;
  23329. }
  23330. let startNode;
  23331. while (node && !dom.isBlock(node)) {
  23332. startNode = node;
  23333. node = node.previousSibling;
  23334. }
  23335. if (startNode && editor.schema.isValidChild(rootBlockName, newBlockName.toLowerCase())) {
  23336. const startNodeParent = startNode.parentNode;
  23337. const newBlock = dom.create(newBlockName);
  23338. setForcedBlockAttrs(editor, newBlock);
  23339. startNodeParent.insertBefore(newBlock, startNode);
  23340. node = startNode;
  23341. while (node && !dom.isBlock(node)) {
  23342. const next = node.nextSibling;
  23343. newBlock.appendChild(node);
  23344. node = next;
  23345. }
  23346. rng.setStart(container, offset);
  23347. rng.setEnd(container, offset);
  23348. }
  23349. }
  23350. return container;
  23351. };
  23352. const addBrToBlockIfNeeded = (dom, block) => {
  23353. block.normalize();
  23354. const lastChild = block.lastChild;
  23355. if (!lastChild || isElement$6(lastChild) && /^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true))) {
  23356. dom.add(block, 'br');
  23357. }
  23358. };
  23359. const shouldEndContainer = (editor, container) => {
  23360. const optionValue = shouldEndContainerOnEmptyBlock(editor);
  23361. if (isNullable(container)) {
  23362. return false;
  23363. } else if (isString(optionValue)) {
  23364. return contains$2(Tools.explode(optionValue), container.nodeName.toLowerCase());
  23365. } else {
  23366. return optionValue;
  23367. }
  23368. };
  23369. const insert$2 = (editor, evt) => {
  23370. let container;
  23371. let offset;
  23372. let parentBlockName;
  23373. let containerBlock;
  23374. let isAfterLastNodeInContainer = false;
  23375. const dom = editor.dom;
  23376. const schema = editor.schema, nonEmptyElementsMap = schema.getNonEmptyElements();
  23377. const rng = editor.selection.getRng();
  23378. const newBlockName = getForcedRootBlock(editor);
  23379. const createNewBlock = name => {
  23380. let node = container;
  23381. const textInlineElements = schema.getTextInlineElements();
  23382. let block;
  23383. if (name || parentBlockName === 'TABLE' || parentBlockName === 'HR') {
  23384. block = dom.create(name || newBlockName);
  23385. } else {
  23386. block = parentBlock.cloneNode(false);
  23387. }
  23388. let caretNode = block;
  23389. if (shouldKeepStyles(editor) === false) {
  23390. dom.setAttrib(block, 'style', null);
  23391. dom.setAttrib(block, 'class', null);
  23392. } else {
  23393. do {
  23394. if (textInlineElements[node.nodeName]) {
  23395. if (isCaretNode(node) || isBookmarkNode$1(node)) {
  23396. continue;
  23397. }
  23398. const clonedNode = node.cloneNode(false);
  23399. dom.setAttrib(clonedNode, 'id', '');
  23400. if (block.hasChildNodes()) {
  23401. clonedNode.appendChild(block.firstChild);
  23402. block.appendChild(clonedNode);
  23403. } else {
  23404. caretNode = clonedNode;
  23405. block.appendChild(clonedNode);
  23406. }
  23407. }
  23408. } while ((node = node.parentNode) && node !== editableRoot);
  23409. }
  23410. setForcedBlockAttrs(editor, block);
  23411. emptyBlock(caretNode);
  23412. return block;
  23413. };
  23414. const isCaretAtStartOrEndOfBlock = start => {
  23415. const normalizedOffset = normalizeZwspOffset(start, container, offset);
  23416. if (isText$a(container) && (start ? normalizedOffset > 0 : normalizedOffset < container.data.length)) {
  23417. return false;
  23418. }
  23419. if (container.parentNode === parentBlock && isAfterLastNodeInContainer && !start) {
  23420. return true;
  23421. }
  23422. if (start && isElement$6(container) && container === parentBlock.firstChild) {
  23423. return true;
  23424. }
  23425. if (containerAndSiblingName(container, 'TABLE') || containerAndSiblingName(container, 'HR')) {
  23426. return isAfterLastNodeInContainer && !start || !isAfterLastNodeInContainer && start;
  23427. }
  23428. const walker = new DomTreeWalker(container, parentBlock);
  23429. if (isText$a(container)) {
  23430. if (start && normalizedOffset === 0) {
  23431. walker.prev();
  23432. } else if (!start && normalizedOffset === container.data.length) {
  23433. walker.next();
  23434. }
  23435. }
  23436. let node;
  23437. while (node = walker.current()) {
  23438. if (isElement$6(node)) {
  23439. if (!node.getAttribute('data-mce-bogus')) {
  23440. const name = node.nodeName.toLowerCase();
  23441. if (nonEmptyElementsMap[name] && name !== 'br') {
  23442. return false;
  23443. }
  23444. }
  23445. } else if (isText$a(node) && !isWhitespaceText(node.data)) {
  23446. return false;
  23447. }
  23448. if (start) {
  23449. walker.prev();
  23450. } else {
  23451. walker.next();
  23452. }
  23453. }
  23454. return true;
  23455. };
  23456. const insertNewBlockAfter = () => {
  23457. let block;
  23458. if (/^(H[1-6]|PRE|FIGURE)$/.test(parentBlockName) && containerBlockName !== 'HGROUP') {
  23459. block = createNewBlock(newBlockName);
  23460. } else {
  23461. block = createNewBlock();
  23462. }
  23463. if (shouldEndContainer(editor, containerBlock) && canSplitBlock(dom, containerBlock) && dom.isEmpty(parentBlock)) {
  23464. block = dom.split(containerBlock, parentBlock);
  23465. } else {
  23466. dom.insertAfter(block, parentBlock);
  23467. }
  23468. moveToCaretPosition(editor, block);
  23469. return block;
  23470. };
  23471. normalize$2(dom, rng).each(normRng => {
  23472. rng.setStart(normRng.startContainer, normRng.startOffset);
  23473. rng.setEnd(normRng.endContainer, normRng.endOffset);
  23474. });
  23475. container = rng.startContainer;
  23476. offset = rng.startOffset;
  23477. const shiftKey = !!(evt && evt.shiftKey);
  23478. const ctrlKey = !!(evt && evt.ctrlKey);
  23479. if (isElement$6(container) && container.hasChildNodes()) {
  23480. isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
  23481. container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
  23482. if (isAfterLastNodeInContainer && isText$a(container)) {
  23483. offset = container.data.length;
  23484. } else {
  23485. offset = 0;
  23486. }
  23487. }
  23488. const editableRoot = getEditableRoot(dom, container);
  23489. if (!editableRoot || isWithinNonEditableList(editor, container)) {
  23490. return;
  23491. }
  23492. if (!shiftKey) {
  23493. container = wrapSelfAndSiblingsInDefaultBlock(editor, newBlockName, rng, container, offset);
  23494. }
  23495. let parentBlock = dom.getParent(container, dom.isBlock) || dom.getRoot();
  23496. containerBlock = isNonNullable(parentBlock === null || parentBlock === void 0 ? void 0 : parentBlock.parentNode) ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
  23497. parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : '';
  23498. const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
  23499. if (containerBlockName === 'LI' && !ctrlKey) {
  23500. const liBlock = containerBlock;
  23501. parentBlock = liBlock;
  23502. containerBlock = liBlock.parentNode;
  23503. parentBlockName = containerBlockName;
  23504. }
  23505. if (/^(LI|DT|DD)$/.test(parentBlockName) && isElement$6(containerBlock)) {
  23506. if (dom.isEmpty(parentBlock)) {
  23507. insert$3(editor, createNewBlock, containerBlock, parentBlock, newBlockName);
  23508. return;
  23509. }
  23510. }
  23511. if (parentBlock === editor.getBody()) {
  23512. return;
  23513. }
  23514. const parentBlockParent = parentBlock.parentNode;
  23515. let newBlock;
  23516. if (isCaretContainerBlock$1(parentBlock)) {
  23517. newBlock = showCaretContainerBlock(parentBlock);
  23518. if (dom.isEmpty(parentBlock)) {
  23519. emptyBlock(parentBlock);
  23520. }
  23521. setForcedBlockAttrs(editor, newBlock);
  23522. moveToCaretPosition(editor, newBlock);
  23523. } else if (isCaretAtStartOrEndOfBlock(false)) {
  23524. newBlock = insertNewBlockAfter();
  23525. } else if (isCaretAtStartOrEndOfBlock(true) && parentBlockParent) {
  23526. newBlock = parentBlockParent.insertBefore(createNewBlock(), parentBlock);
  23527. moveToCaretPosition(editor, containerAndSiblingName(parentBlock, 'HR') ? newBlock : parentBlock);
  23528. } else {
  23529. const tmpRng = includeZwspInRange(rng).cloneRange();
  23530. tmpRng.setEndAfter(parentBlock);
  23531. const fragment = tmpRng.extractContents();
  23532. trimZwsp(fragment);
  23533. trimLeadingLineBreaks(fragment);
  23534. newBlock = fragment.firstChild;
  23535. dom.insertAfter(fragment, parentBlock);
  23536. trimInlineElementsOnLeftSideOfBlock(dom, nonEmptyElementsMap, newBlock);
  23537. addBrToBlockIfNeeded(dom, parentBlock);
  23538. if (dom.isEmpty(parentBlock)) {
  23539. emptyBlock(parentBlock);
  23540. }
  23541. newBlock.normalize();
  23542. if (dom.isEmpty(newBlock)) {
  23543. dom.remove(newBlock);
  23544. insertNewBlockAfter();
  23545. } else {
  23546. setForcedBlockAttrs(editor, newBlock);
  23547. moveToCaretPosition(editor, newBlock);
  23548. }
  23549. }
  23550. dom.setAttrib(newBlock, 'id', '');
  23551. editor.dispatch('NewBlock', { newBlock });
  23552. };
  23553. const fakeEventName$1 = 'insertParagraph';
  23554. const blockbreak = {
  23555. insert: insert$2,
  23556. fakeEventName: fakeEventName$1
  23557. };
  23558. const hasRightSideContent = (schema, container, parentBlock) => {
  23559. const walker = new DomTreeWalker(container, parentBlock);
  23560. let node;
  23561. const nonEmptyElementsMap = schema.getNonEmptyElements();
  23562. while (node = walker.next()) {
  23563. if (nonEmptyElementsMap[node.nodeName.toLowerCase()] || isText$a(node) && node.length > 0) {
  23564. return true;
  23565. }
  23566. }
  23567. return false;
  23568. };
  23569. const moveSelectionToBr = (editor, brElm, extraBr) => {
  23570. const rng = editor.dom.createRng();
  23571. if (!extraBr) {
  23572. rng.setStartAfter(brElm);
  23573. rng.setEndAfter(brElm);
  23574. } else {
  23575. rng.setStartBefore(brElm);
  23576. rng.setEndBefore(brElm);
  23577. }
  23578. editor.selection.setRng(rng);
  23579. scrollRangeIntoView(editor, rng);
  23580. };
  23581. const insertBrAtCaret = (editor, evt) => {
  23582. const selection = editor.selection;
  23583. const dom = editor.dom;
  23584. const rng = selection.getRng();
  23585. let brElm;
  23586. let extraBr = false;
  23587. normalize$2(dom, rng).each(normRng => {
  23588. rng.setStart(normRng.startContainer, normRng.startOffset);
  23589. rng.setEnd(normRng.endContainer, normRng.endOffset);
  23590. });
  23591. let offset = rng.startOffset;
  23592. let container = rng.startContainer;
  23593. if (isElement$6(container) && container.hasChildNodes()) {
  23594. const isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
  23595. container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
  23596. if (isAfterLastNodeInContainer && isText$a(container)) {
  23597. offset = container.data.length;
  23598. } else {
  23599. offset = 0;
  23600. }
  23601. }
  23602. let parentBlock = dom.getParent(container, dom.isBlock);
  23603. const containerBlock = parentBlock && parentBlock.parentNode ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
  23604. const containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : '';
  23605. const isControlKey = !!(evt && evt.ctrlKey);
  23606. if (containerBlockName === 'LI' && !isControlKey) {
  23607. parentBlock = containerBlock;
  23608. }
  23609. if (isText$a(container) && offset >= container.data.length) {
  23610. if (!hasRightSideContent(editor.schema, container, parentBlock || dom.getRoot())) {
  23611. brElm = dom.create('br');
  23612. rng.insertNode(brElm);
  23613. rng.setStartAfter(brElm);
  23614. rng.setEndAfter(brElm);
  23615. extraBr = true;
  23616. }
  23617. }
  23618. brElm = dom.create('br');
  23619. rangeInsertNode(dom, rng, brElm);
  23620. moveSelectionToBr(editor, brElm, extraBr);
  23621. editor.undoManager.add();
  23622. };
  23623. const insertBrBefore = (editor, inline) => {
  23624. const br = SugarElement.fromTag('br');
  23625. before$3(SugarElement.fromDom(inline), br);
  23626. editor.undoManager.add();
  23627. };
  23628. const insertBrAfter = (editor, inline) => {
  23629. if (!hasBrAfter(editor.getBody(), inline)) {
  23630. after$4(SugarElement.fromDom(inline), SugarElement.fromTag('br'));
  23631. }
  23632. const br = SugarElement.fromTag('br');
  23633. after$4(SugarElement.fromDom(inline), br);
  23634. moveSelectionToBr(editor, br.dom, false);
  23635. editor.undoManager.add();
  23636. };
  23637. const isBeforeBr = pos => {
  23638. return isBr$6(pos.getNode());
  23639. };
  23640. const hasBrAfter = (rootNode, startNode) => {
  23641. if (isBeforeBr(CaretPosition.after(startNode))) {
  23642. return true;
  23643. } else {
  23644. return nextPosition(rootNode, CaretPosition.after(startNode)).map(pos => {
  23645. return isBr$6(pos.getNode());
  23646. }).getOr(false);
  23647. }
  23648. };
  23649. const isAnchorLink = elm => {
  23650. return elm && elm.nodeName === 'A' && 'href' in elm;
  23651. };
  23652. const isInsideAnchor = location => {
  23653. return location.fold(never, isAnchorLink, isAnchorLink, never);
  23654. };
  23655. const readInlineAnchorLocation = editor => {
  23656. const isInlineTarget$1 = curry(isInlineTarget, editor);
  23657. const position = CaretPosition.fromRangeStart(editor.selection.getRng());
  23658. return readLocation(isInlineTarget$1, editor.getBody(), position).filter(isInsideAnchor);
  23659. };
  23660. const insertBrOutsideAnchor = (editor, location) => {
  23661. location.fold(noop, curry(insertBrBefore, editor), curry(insertBrAfter, editor), noop);
  23662. };
  23663. const insert$1 = (editor, evt) => {
  23664. const anchorLocation = readInlineAnchorLocation(editor);
  23665. if (anchorLocation.isSome()) {
  23666. anchorLocation.each(curry(insertBrOutsideAnchor, editor));
  23667. } else {
  23668. insertBrAtCaret(editor, evt);
  23669. }
  23670. };
  23671. const fakeEventName = 'insertLineBreak';
  23672. const linebreak = {
  23673. insert: insert$1,
  23674. fakeEventName
  23675. };
  23676. const matchesSelector = (editor, selector) => {
  23677. return getParentBlock$1(editor).filter(parentBlock => {
  23678. return selector.length > 0 && is$1(SugarElement.fromDom(parentBlock), selector);
  23679. }).isSome();
  23680. };
  23681. const shouldInsertBr = editor => {
  23682. return matchesSelector(editor, getBrNewLineSelector(editor));
  23683. };
  23684. const shouldBlockNewLine$1 = editor => {
  23685. return matchesSelector(editor, getNoNewLineSelector(editor));
  23686. };
  23687. const newLineAction = Adt.generate([
  23688. { br: [] },
  23689. { block: [] },
  23690. { none: [] }
  23691. ]);
  23692. const shouldBlockNewLine = (editor, _shiftKey) => {
  23693. return shouldBlockNewLine$1(editor);
  23694. };
  23695. const inListBlock = requiredState => {
  23696. return (editor, _shiftKey) => {
  23697. return isListItemParentBlock(editor) === requiredState;
  23698. };
  23699. };
  23700. const inBlock = (blockName, requiredState) => (editor, _shiftKey) => {
  23701. const state = getParentBlockName(editor) === blockName.toUpperCase();
  23702. return state === requiredState;
  23703. };
  23704. const inCefBlock = editor => {
  23705. const editableRoot = getEditableRoot(editor.dom, editor.selection.getStart());
  23706. return isNullable(editableRoot);
  23707. };
  23708. const inPreBlock = requiredState => inBlock('pre', requiredState);
  23709. const inSummaryBlock = () => inBlock('summary', true);
  23710. const shouldPutBrInPre = requiredState => {
  23711. return (editor, _shiftKey) => {
  23712. return shouldPutBrInPre$1(editor) === requiredState;
  23713. };
  23714. };
  23715. const inBrContext = (editor, _shiftKey) => {
  23716. return shouldInsertBr(editor);
  23717. };
  23718. const hasShiftKey = (_editor, shiftKey) => {
  23719. return shiftKey;
  23720. };
  23721. const canInsertIntoEditableRoot = editor => {
  23722. const forcedRootBlock = getForcedRootBlock(editor);
  23723. const rootEditable = getEditableRoot(editor.dom, editor.selection.getStart());
  23724. return isNonNullable(rootEditable) && editor.schema.isValidChild(rootEditable.nodeName, forcedRootBlock);
  23725. };
  23726. const match = (predicates, action) => {
  23727. return (editor, shiftKey) => {
  23728. const isMatch = foldl(predicates, (res, p) => {
  23729. return res && p(editor, shiftKey);
  23730. }, true);
  23731. return isMatch ? Optional.some(action) : Optional.none();
  23732. };
  23733. };
  23734. const getAction = (editor, evt) => {
  23735. return evaluateUntil([
  23736. match([shouldBlockNewLine], newLineAction.none()),
  23737. match([
  23738. inPreBlock(true),
  23739. inCefBlock
  23740. ], newLineAction.none()),
  23741. match([inSummaryBlock()], newLineAction.br()),
  23742. match([
  23743. inPreBlock(true),
  23744. shouldPutBrInPre(false),
  23745. hasShiftKey
  23746. ], newLineAction.br()),
  23747. match([
  23748. inPreBlock(true),
  23749. shouldPutBrInPre(false)
  23750. ], newLineAction.block()),
  23751. match([
  23752. inPreBlock(true),
  23753. shouldPutBrInPre(true),
  23754. hasShiftKey
  23755. ], newLineAction.block()),
  23756. match([
  23757. inPreBlock(true),
  23758. shouldPutBrInPre(true)
  23759. ], newLineAction.br()),
  23760. match([
  23761. inListBlock(true),
  23762. hasShiftKey
  23763. ], newLineAction.br()),
  23764. match([inListBlock(true)], newLineAction.block()),
  23765. match([inBrContext], newLineAction.br()),
  23766. match([hasShiftKey], newLineAction.br()),
  23767. match([canInsertIntoEditableRoot], newLineAction.block())
  23768. ], [
  23769. editor,
  23770. !!(evt && evt.shiftKey)
  23771. ]).getOr(newLineAction.none());
  23772. };
  23773. const insertBreak = (breakType, editor, evt) => {
  23774. if (!editor.selection.isCollapsed()) {
  23775. execEditorDeleteCommand(editor);
  23776. }
  23777. if (isNonNullable(evt)) {
  23778. const event = fireFakeBeforeInputEvent(editor, breakType.fakeEventName);
  23779. if (event.isDefaultPrevented()) {
  23780. return;
  23781. }
  23782. }
  23783. breakType.insert(editor, evt);
  23784. if (isNonNullable(evt)) {
  23785. fireFakeInputEvent(editor, breakType.fakeEventName);
  23786. }
  23787. };
  23788. const insert = (editor, evt) => {
  23789. const br = () => insertBreak(linebreak, editor, evt);
  23790. const block = () => insertBreak(blockbreak, editor, evt);
  23791. const logicalAction = getAction(editor, evt);
  23792. switch (getNewlineBehavior(editor)) {
  23793. case 'linebreak':
  23794. logicalAction.fold(br, br, noop);
  23795. break;
  23796. case 'block':
  23797. logicalAction.fold(block, block, noop);
  23798. break;
  23799. case 'invert':
  23800. logicalAction.fold(block, br, noop);
  23801. break;
  23802. default:
  23803. logicalAction.fold(br, block, noop);
  23804. break;
  23805. }
  23806. };
  23807. const handleEnterKeyEvent = (editor, event) => {
  23808. if (event.isDefaultPrevented()) {
  23809. return;
  23810. }
  23811. event.preventDefault();
  23812. endTypingLevelIgnoreLocks(editor.undoManager);
  23813. editor.undoManager.transact(() => {
  23814. insert(editor, event);
  23815. });
  23816. };
  23817. const setup$h = editor => {
  23818. editor.on('keydown', event => {
  23819. if (event.keyCode === VK.ENTER) {
  23820. handleEnterKeyEvent(editor, event);
  23821. }
  23822. });
  23823. };
  23824. const executeKeydownOverride$2 = (editor, caret, evt) => {
  23825. const isMac = Env.os.isMacOS() || Env.os.isiOS();
  23826. execute([
  23827. {
  23828. keyCode: VK.END,
  23829. action: action(moveToLineEndPoint$1, editor, true)
  23830. },
  23831. {
  23832. keyCode: VK.HOME,
  23833. action: action(moveToLineEndPoint$1, editor, false)
  23834. },
  23835. ...!isMac ? [
  23836. {
  23837. keyCode: VK.HOME,
  23838. action: action(selectToEndPoint, editor, false),
  23839. ctrlKey: true,
  23840. shiftKey: true
  23841. },
  23842. {
  23843. keyCode: VK.END,
  23844. action: action(selectToEndPoint, editor, true),
  23845. ctrlKey: true,
  23846. shiftKey: true
  23847. }
  23848. ] : [],
  23849. {
  23850. keyCode: VK.END,
  23851. action: action(moveToLineEndPoint, editor, true)
  23852. },
  23853. {
  23854. keyCode: VK.HOME,
  23855. action: action(moveToLineEndPoint, editor, false)
  23856. },
  23857. {
  23858. keyCode: VK.END,
  23859. action: action(moveToLineEndPoint$2, editor, true, caret)
  23860. },
  23861. {
  23862. keyCode: VK.HOME,
  23863. action: action(moveToLineEndPoint$2, editor, false, caret)
  23864. }
  23865. ], evt).each(_ => {
  23866. evt.preventDefault();
  23867. });
  23868. };
  23869. const setup$g = (editor, caret) => {
  23870. editor.on('keydown', evt => {
  23871. if (!evt.isDefaultPrevented()) {
  23872. executeKeydownOverride$2(editor, caret, evt);
  23873. }
  23874. });
  23875. };
  23876. const setup$f = editor => {
  23877. editor.on('input', e => {
  23878. if (!e.isComposing) {
  23879. normalizeNbspsInEditor(editor);
  23880. }
  23881. });
  23882. };
  23883. const platform = detect$2();
  23884. const executeKeyupAction = (editor, caret, evt) => {
  23885. execute([
  23886. {
  23887. keyCode: VK.PAGE_UP,
  23888. action: action(moveToLineEndPoint$2, editor, false, caret)
  23889. },
  23890. {
  23891. keyCode: VK.PAGE_DOWN,
  23892. action: action(moveToLineEndPoint$2, editor, true, caret)
  23893. }
  23894. ], evt);
  23895. };
  23896. const stopImmediatePropagation = e => e.stopImmediatePropagation();
  23897. const isPageUpDown = evt => evt.keyCode === VK.PAGE_UP || evt.keyCode === VK.PAGE_DOWN;
  23898. const setNodeChangeBlocker = (blocked, editor, block) => {
  23899. if (block && !blocked.get()) {
  23900. editor.on('NodeChange', stopImmediatePropagation, true);
  23901. } else if (!block && blocked.get()) {
  23902. editor.off('NodeChange', stopImmediatePropagation);
  23903. }
  23904. blocked.set(block);
  23905. };
  23906. const setup$e = (editor, caret) => {
  23907. if (platform.os.isMacOS()) {
  23908. return;
  23909. }
  23910. const blocked = Cell(false);
  23911. editor.on('keydown', evt => {
  23912. if (isPageUpDown(evt)) {
  23913. setNodeChangeBlocker(blocked, editor, true);
  23914. }
  23915. });
  23916. editor.on('keyup', evt => {
  23917. if (!evt.isDefaultPrevented()) {
  23918. executeKeyupAction(editor, caret, evt);
  23919. }
  23920. if (isPageUpDown(evt) && blocked.get()) {
  23921. setNodeChangeBlocker(blocked, editor, false);
  23922. editor.nodeChanged();
  23923. }
  23924. });
  23925. };
  23926. const insertTextAtPosition = (text, pos) => {
  23927. const container = pos.container();
  23928. const offset = pos.offset();
  23929. if (isText$a(container)) {
  23930. container.insertData(offset, text);
  23931. return Optional.some(CaretPosition(container, offset + text.length));
  23932. } else {
  23933. return getElementFromPosition(pos).map(elm => {
  23934. const textNode = SugarElement.fromText(text);
  23935. if (pos.isAtEnd()) {
  23936. after$4(elm, textNode);
  23937. } else {
  23938. before$3(elm, textNode);
  23939. }
  23940. return CaretPosition(textNode.dom, text.length);
  23941. });
  23942. }
  23943. };
  23944. const insertNbspAtPosition = curry(insertTextAtPosition, nbsp);
  23945. const insertSpaceAtPosition = curry(insertTextAtPosition, ' ');
  23946. const locationToCaretPosition = root => location => location.fold(element => prevPosition(root.dom, CaretPosition.before(element)), element => firstPositionIn(element), element => lastPositionIn(element), element => nextPosition(root.dom, CaretPosition.after(element)));
  23947. const insertInlineBoundarySpaceOrNbsp = (root, pos) => checkPos => needsToHaveNbsp(root, checkPos) ? insertNbspAtPosition(pos) : insertSpaceAtPosition(pos);
  23948. const setSelection = editor => pos => {
  23949. editor.selection.setRng(pos.toRange());
  23950. editor.nodeChanged();
  23951. return true;
  23952. };
  23953. const insertSpaceOrNbspAtSelection = editor => {
  23954. const pos = CaretPosition.fromRangeStart(editor.selection.getRng());
  23955. const root = SugarElement.fromDom(editor.getBody());
  23956. if (editor.selection.isCollapsed()) {
  23957. const isInlineTarget$1 = curry(isInlineTarget, editor);
  23958. const caretPosition = CaretPosition.fromRangeStart(editor.selection.getRng());
  23959. return readLocation(isInlineTarget$1, editor.getBody(), caretPosition).bind(locationToCaretPosition(root)).map(checkPos => () => insertInlineBoundarySpaceOrNbsp(root, pos)(checkPos).each(setSelection(editor)));
  23960. } else {
  23961. return Optional.none();
  23962. }
  23963. };
  23964. const executeKeydownOverride$1 = (editor, evt) => {
  23965. executeWithDelayedAction([{
  23966. keyCode: VK.SPACEBAR,
  23967. action: action(insertSpaceOrNbspAtSelection, editor)
  23968. }], evt).each(applyAction => {
  23969. evt.preventDefault();
  23970. const event = fireFakeBeforeInputEvent(editor, 'insertText', { data: ' ' });
  23971. if (!event.isDefaultPrevented()) {
  23972. applyAction();
  23973. fireFakeInputEvent(editor, 'insertText', { data: ' ' });
  23974. }
  23975. });
  23976. };
  23977. const setup$d = editor => {
  23978. editor.on('keydown', evt => {
  23979. if (!evt.isDefaultPrevented()) {
  23980. executeKeydownOverride$1(editor, evt);
  23981. }
  23982. });
  23983. };
  23984. const tableTabNavigation = editor => {
  23985. if (hasTableTabNavigation(editor)) {
  23986. return [
  23987. {
  23988. keyCode: VK.TAB,
  23989. action: action(handleTab, editor, true)
  23990. },
  23991. {
  23992. keyCode: VK.TAB,
  23993. shiftKey: true,
  23994. action: action(handleTab, editor, false)
  23995. }
  23996. ];
  23997. } else {
  23998. return [];
  23999. }
  24000. };
  24001. const executeKeydownOverride = (editor, evt) => {
  24002. execute([...tableTabNavigation(editor)], evt).each(_ => {
  24003. evt.preventDefault();
  24004. });
  24005. };
  24006. const setup$c = editor => {
  24007. editor.on('keydown', evt => {
  24008. if (!evt.isDefaultPrevented()) {
  24009. executeKeydownOverride(editor, evt);
  24010. }
  24011. });
  24012. };
  24013. const setup$b = editor => {
  24014. editor.addShortcut('Meta+P', '', 'mcePrint');
  24015. setup$j(editor);
  24016. if (isRtc(editor)) {
  24017. return Cell(null);
  24018. } else {
  24019. const caret = setupSelectedState(editor);
  24020. setup$l(editor);
  24021. setup$k(editor, caret);
  24022. setup$i(editor, caret);
  24023. setup$h(editor);
  24024. setup$d(editor);
  24025. setup$f(editor);
  24026. setup$c(editor);
  24027. setup$g(editor, caret);
  24028. setup$e(editor, caret);
  24029. return caret;
  24030. }
  24031. };
  24032. class NodeChange {
  24033. constructor(editor) {
  24034. this.lastPath = [];
  24035. this.editor = editor;
  24036. let lastRng;
  24037. const self = this;
  24038. if (!('onselectionchange' in editor.getDoc())) {
  24039. editor.on('NodeChange click mouseup keyup focus', e => {
  24040. const nativeRng = editor.selection.getRng();
  24041. const fakeRng = {
  24042. startContainer: nativeRng.startContainer,
  24043. startOffset: nativeRng.startOffset,
  24044. endContainer: nativeRng.endContainer,
  24045. endOffset: nativeRng.endOffset
  24046. };
  24047. if (e.type === 'nodechange' || !isEq$4(fakeRng, lastRng)) {
  24048. editor.dispatch('SelectionChange');
  24049. }
  24050. lastRng = fakeRng;
  24051. });
  24052. }
  24053. editor.on('contextmenu', () => {
  24054. editor.dispatch('SelectionChange');
  24055. });
  24056. editor.on('SelectionChange', () => {
  24057. const startElm = editor.selection.getStart(true);
  24058. if (!startElm) {
  24059. return;
  24060. }
  24061. if (hasAnyRanges(editor) && !self.isSameElementPath(startElm) && editor.dom.isChildOf(startElm, editor.getBody())) {
  24062. editor.nodeChanged({ selectionChange: true });
  24063. }
  24064. });
  24065. editor.on('mouseup', e => {
  24066. if (!e.isDefaultPrevented() && hasAnyRanges(editor)) {
  24067. if (editor.selection.getNode().nodeName === 'IMG') {
  24068. Delay.setEditorTimeout(editor, () => {
  24069. editor.nodeChanged();
  24070. });
  24071. } else {
  24072. editor.nodeChanged();
  24073. }
  24074. }
  24075. });
  24076. }
  24077. nodeChanged(args = {}) {
  24078. const selection = this.editor.selection;
  24079. let node;
  24080. if (this.editor.initialized && selection && !shouldDisableNodeChange(this.editor) && !this.editor.mode.isReadOnly()) {
  24081. const root = this.editor.getBody();
  24082. node = selection.getStart(true) || root;
  24083. if (node.ownerDocument !== this.editor.getDoc() || !this.editor.dom.isChildOf(node, root)) {
  24084. node = root;
  24085. }
  24086. const parents = [];
  24087. this.editor.dom.getParent(node, node => {
  24088. if (node === root) {
  24089. return true;
  24090. } else {
  24091. parents.push(node);
  24092. return false;
  24093. }
  24094. });
  24095. this.editor.dispatch('NodeChange', {
  24096. ...args,
  24097. element: node,
  24098. parents
  24099. });
  24100. }
  24101. }
  24102. isSameElementPath(startElm) {
  24103. let i;
  24104. const editor = this.editor;
  24105. const currentPath = reverse(editor.dom.getParents(startElm, always, editor.getBody()));
  24106. if (currentPath.length === this.lastPath.length) {
  24107. for (i = currentPath.length; i >= 0; i--) {
  24108. if (currentPath[i] !== this.lastPath[i]) {
  24109. break;
  24110. }
  24111. }
  24112. if (i === -1) {
  24113. this.lastPath = currentPath;
  24114. return true;
  24115. }
  24116. }
  24117. this.lastPath = currentPath;
  24118. return false;
  24119. }
  24120. }
  24121. const internalMimeType = 'x-tinymce/html';
  24122. const internalHtmlMime = constant(internalMimeType);
  24123. const internalMark = '<!-- ' + internalMimeType + ' -->';
  24124. const mark = html => internalMark + html;
  24125. const unmark = html => html.replace(internalMark, '');
  24126. const isMarked = html => html.indexOf(internalMark) !== -1;
  24127. const isPlainText = text => {
  24128. return !/<(?:\/?(?!(?:div|p|br|span)>)\w+|(?:(?!(?:span style="white-space:\s?pre;?">)|br\s?\/>))\w+\s[^>]+)>/i.test(text);
  24129. };
  24130. const openContainer = (rootTag, rootAttrs) => {
  24131. let tag = '<' + rootTag;
  24132. const attrs = mapToArray(rootAttrs, (value, key) => key + '="' + Entities.encodeAllRaw(value) + '"');
  24133. if (attrs.length) {
  24134. tag += ' ' + attrs.join(' ');
  24135. }
  24136. return tag + '>';
  24137. };
  24138. const toBlockElements = (text, rootTag, rootAttrs) => {
  24139. const blocks = text.split(/\n\n/);
  24140. const tagOpen = openContainer(rootTag, rootAttrs);
  24141. const tagClose = '</' + rootTag + '>';
  24142. const paragraphs = map$3(blocks, p => {
  24143. return p.split(/\n/).join('<br />');
  24144. });
  24145. const stitch = p => {
  24146. return tagOpen + p + tagClose;
  24147. };
  24148. return paragraphs.length === 1 ? paragraphs[0] : map$3(paragraphs, stitch).join('');
  24149. };
  24150. const pasteBinDefaultContent = '%MCEPASTEBIN%';
  24151. const create$6 = (editor, lastRngCell) => {
  24152. const {dom, selection} = editor;
  24153. const body = editor.getBody();
  24154. lastRngCell.set(selection.getRng());
  24155. const pasteBinElm = dom.add(editor.getBody(), 'div', {
  24156. 'id': 'mcepastebin',
  24157. 'class': 'mce-pastebin',
  24158. 'contentEditable': true,
  24159. 'data-mce-bogus': 'all',
  24160. 'style': 'position: fixed; top: 50%; width: 10px; height: 10px; overflow: hidden; opacity: 0'
  24161. }, pasteBinDefaultContent);
  24162. if (Env.browser.isFirefox()) {
  24163. dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) === 'rtl' ? 65535 : -65535);
  24164. }
  24165. dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', e => {
  24166. e.stopPropagation();
  24167. });
  24168. pasteBinElm.focus();
  24169. selection.select(pasteBinElm, true);
  24170. };
  24171. const remove = (editor, lastRngCell) => {
  24172. const dom = editor.dom;
  24173. if (getEl(editor)) {
  24174. let pasteBinClone;
  24175. const lastRng = lastRngCell.get();
  24176. while (pasteBinClone = getEl(editor)) {
  24177. dom.remove(pasteBinClone);
  24178. dom.unbind(pasteBinClone);
  24179. }
  24180. if (lastRng) {
  24181. editor.selection.setRng(lastRng);
  24182. }
  24183. }
  24184. lastRngCell.set(null);
  24185. };
  24186. const getEl = editor => editor.dom.get('mcepastebin');
  24187. const isPasteBin = elm => isNonNullable(elm) && elm.id === 'mcepastebin';
  24188. const getHtml = editor => {
  24189. const dom = editor.dom;
  24190. const copyAndRemove = (toElm, fromElm) => {
  24191. toElm.appendChild(fromElm);
  24192. dom.remove(fromElm, true);
  24193. };
  24194. const [pasteBinElm, ...pasteBinClones] = filter$5(editor.getBody().childNodes, isPasteBin);
  24195. each$e(pasteBinClones, pasteBinClone => {
  24196. copyAndRemove(pasteBinElm, pasteBinClone);
  24197. });
  24198. const dirtyWrappers = dom.select('div[id=mcepastebin]', pasteBinElm);
  24199. for (let i = dirtyWrappers.length - 1; i >= 0; i--) {
  24200. const cleanWrapper = dom.create('div');
  24201. pasteBinElm.insertBefore(cleanWrapper, dirtyWrappers[i]);
  24202. copyAndRemove(cleanWrapper, dirtyWrappers[i]);
  24203. }
  24204. return pasteBinElm ? pasteBinElm.innerHTML : '';
  24205. };
  24206. const isDefaultPasteBinContent = content => content === pasteBinDefaultContent;
  24207. const PasteBin = editor => {
  24208. const lastRng = Cell(null);
  24209. return {
  24210. create: () => create$6(editor, lastRng),
  24211. remove: () => remove(editor, lastRng),
  24212. getEl: () => getEl(editor),
  24213. getHtml: () => getHtml(editor),
  24214. getLastRng: lastRng.get
  24215. };
  24216. };
  24217. const filter = (content, items) => {
  24218. Tools.each(items, v => {
  24219. if (is$4(v, RegExp)) {
  24220. content = content.replace(v, '');
  24221. } else {
  24222. content = content.replace(v[0], v[1]);
  24223. }
  24224. });
  24225. return content;
  24226. };
  24227. const innerText = html => {
  24228. const schema = Schema();
  24229. const domParser = DomParser({}, schema);
  24230. let text = '';
  24231. const voidElements = schema.getVoidElements();
  24232. const ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
  24233. const blockElements = schema.getBlockElements();
  24234. const walk = node => {
  24235. const name = node.name, currentNode = node;
  24236. if (name === 'br') {
  24237. text += '\n';
  24238. return;
  24239. }
  24240. if (name === 'wbr') {
  24241. return;
  24242. }
  24243. if (voidElements[name]) {
  24244. text += ' ';
  24245. }
  24246. if (ignoreElements[name]) {
  24247. text += ' ';
  24248. return;
  24249. }
  24250. if (node.type === 3) {
  24251. text += node.value;
  24252. }
  24253. if (!(node.name in schema.getVoidElements())) {
  24254. let currentNode = node.firstChild;
  24255. if (currentNode) {
  24256. do {
  24257. walk(currentNode);
  24258. } while (currentNode = currentNode.next);
  24259. }
  24260. }
  24261. if (blockElements[name] && currentNode.next) {
  24262. text += '\n';
  24263. if (name === 'p') {
  24264. text += '\n';
  24265. }
  24266. }
  24267. };
  24268. html = filter(html, [/<!\[[^\]]+\]>/g]);
  24269. walk(domParser.parse(html));
  24270. return text;
  24271. };
  24272. const trimHtml = html => {
  24273. const trimSpaces = (all, s1, s2) => {
  24274. if (!s1 && !s2) {
  24275. return ' ';
  24276. }
  24277. return nbsp;
  24278. };
  24279. html = filter(html, [
  24280. /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/ig,
  24281. /<!--StartFragment-->|<!--EndFragment-->/g,
  24282. [
  24283. /( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g,
  24284. trimSpaces
  24285. ],
  24286. /<br class="Apple-interchange-newline">/g,
  24287. /<br>$/i
  24288. ]);
  24289. return html;
  24290. };
  24291. const createIdGenerator = prefix => {
  24292. let count = 0;
  24293. return () => {
  24294. return prefix + count++;
  24295. };
  24296. };
  24297. const getImageMimeType = ext => {
  24298. const lowerExt = ext.toLowerCase();
  24299. const mimeOverrides = {
  24300. jpg: 'jpeg',
  24301. jpe: 'jpeg',
  24302. jfi: 'jpeg',
  24303. jif: 'jpeg',
  24304. jfif: 'jpeg',
  24305. pjpeg: 'jpeg',
  24306. pjp: 'jpeg',
  24307. svg: 'svg+xml'
  24308. };
  24309. return Tools.hasOwn(mimeOverrides, lowerExt) ? 'image/' + mimeOverrides[lowerExt] : 'image/' + lowerExt;
  24310. };
  24311. const preProcess = (editor, html) => {
  24312. const parser = DomParser({}, editor.schema);
  24313. parser.addNodeFilter('meta', nodes => {
  24314. Tools.each(nodes, node => {
  24315. node.remove();
  24316. });
  24317. });
  24318. const fragment = parser.parse(html, {
  24319. forced_root_block: false,
  24320. isRootContent: true
  24321. });
  24322. return HtmlSerializer({ validate: true }, editor.schema).serialize(fragment);
  24323. };
  24324. const processResult = (content, cancelled) => ({
  24325. content,
  24326. cancelled
  24327. });
  24328. const postProcessFilter = (editor, html, internal) => {
  24329. const tempBody = editor.dom.create('div', { style: 'display:none' }, html);
  24330. const postProcessArgs = firePastePostProcess(editor, tempBody, internal);
  24331. return processResult(postProcessArgs.node.innerHTML, postProcessArgs.isDefaultPrevented());
  24332. };
  24333. const filterContent = (editor, content, internal) => {
  24334. const preProcessArgs = firePastePreProcess(editor, content, internal);
  24335. const filteredContent = preProcess(editor, preProcessArgs.content);
  24336. if (editor.hasEventListeners('PastePostProcess') && !preProcessArgs.isDefaultPrevented()) {
  24337. return postProcessFilter(editor, filteredContent, internal);
  24338. } else {
  24339. return processResult(filteredContent, preProcessArgs.isDefaultPrevented());
  24340. }
  24341. };
  24342. const process = (editor, html, internal) => {
  24343. return filterContent(editor, html, internal);
  24344. };
  24345. const pasteHtml$1 = (editor, html) => {
  24346. editor.insertContent(html, {
  24347. merge: shouldPasteMergeFormats(editor),
  24348. paste: true
  24349. });
  24350. return true;
  24351. };
  24352. const isAbsoluteUrl = url => /^https?:\/\/[\w\-\/+=.,!;:&%@^~(){}?#]+$/i.test(url);
  24353. const isImageUrl = (editor, url) => {
  24354. return isAbsoluteUrl(url) && exists(getAllowedImageFileTypes(editor), type => endsWith(url.toLowerCase(), `.${ type.toLowerCase() }`));
  24355. };
  24356. const createImage = (editor, url, pasteHtmlFn) => {
  24357. editor.undoManager.extra(() => {
  24358. pasteHtmlFn(editor, url);
  24359. }, () => {
  24360. editor.insertContent('<img src="' + url + '">');
  24361. });
  24362. return true;
  24363. };
  24364. const createLink = (editor, url, pasteHtmlFn) => {
  24365. editor.undoManager.extra(() => {
  24366. pasteHtmlFn(editor, url);
  24367. }, () => {
  24368. editor.execCommand('mceInsertLink', false, url);
  24369. });
  24370. return true;
  24371. };
  24372. const linkSelection = (editor, html, pasteHtmlFn) => !editor.selection.isCollapsed() && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtmlFn) : false;
  24373. const insertImage = (editor, html, pasteHtmlFn) => isImageUrl(editor, html) ? createImage(editor, html, pasteHtmlFn) : false;
  24374. const smartInsertContent = (editor, html) => {
  24375. Tools.each([
  24376. linkSelection,
  24377. insertImage,
  24378. pasteHtml$1
  24379. ], action => {
  24380. return !action(editor, html, pasteHtml$1);
  24381. });
  24382. };
  24383. const insertContent = (editor, html, pasteAsText) => {
  24384. if (pasteAsText || !isSmartPasteEnabled(editor)) {
  24385. pasteHtml$1(editor, html);
  24386. } else {
  24387. smartInsertContent(editor, html);
  24388. }
  24389. };
  24390. const uniqueId = createIdGenerator('mceclip');
  24391. const doPaste = (editor, content, internal, pasteAsText) => {
  24392. const args = process(editor, content, internal);
  24393. if (!args.cancelled) {
  24394. insertContent(editor, args.content, pasteAsText);
  24395. }
  24396. };
  24397. const pasteHtml = (editor, html, internalFlag) => {
  24398. const internal = internalFlag ? internalFlag : isMarked(html);
  24399. doPaste(editor, unmark(html), internal, false);
  24400. };
  24401. const pasteText = (editor, text) => {
  24402. const encodedText = editor.dom.encode(text).replace(/\r\n/g, '\n');
  24403. const normalizedText = normalize$4(encodedText, getPasteTabSpaces(editor));
  24404. const html = toBlockElements(normalizedText, getForcedRootBlock(editor), getForcedRootBlockAttrs(editor));
  24405. doPaste(editor, html, false, true);
  24406. };
  24407. const getDataTransferItems = dataTransfer => {
  24408. const items = {};
  24409. if (dataTransfer && dataTransfer.types) {
  24410. for (let i = 0; i < dataTransfer.types.length; i++) {
  24411. const contentType = dataTransfer.types[i];
  24412. try {
  24413. items[contentType] = dataTransfer.getData(contentType);
  24414. } catch (ex) {
  24415. items[contentType] = '';
  24416. }
  24417. }
  24418. }
  24419. return items;
  24420. };
  24421. const hasContentType = (clipboardContent, mimeType) => mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
  24422. const hasHtmlOrText = content => hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
  24423. const extractFilename = (editor, str) => {
  24424. const m = str.match(/([\s\S]+?)(?:\.[a-z0-9.]+)$/i);
  24425. return isNonNullable(m) ? editor.dom.encode(m[1]) : undefined;
  24426. };
  24427. const createBlobInfo = (editor, blobCache, file, base64) => {
  24428. const id = uniqueId();
  24429. const useFileName = shouldReuseFileName(editor) && isNonNullable(file.name);
  24430. const name = useFileName ? extractFilename(editor, file.name) : id;
  24431. const filename = useFileName ? file.name : undefined;
  24432. const blobInfo = blobCache.create(id, file, base64, name, filename);
  24433. blobCache.add(blobInfo);
  24434. return blobInfo;
  24435. };
  24436. const pasteImage = (editor, imageItem) => {
  24437. parseDataUri(imageItem.uri).each(({data, type, base64Encoded}) => {
  24438. const base64 = base64Encoded ? data : btoa(data);
  24439. const file = imageItem.file;
  24440. const blobCache = editor.editorUpload.blobCache;
  24441. const existingBlobInfo = blobCache.getByData(base64, type);
  24442. const blobInfo = existingBlobInfo !== null && existingBlobInfo !== void 0 ? existingBlobInfo : createBlobInfo(editor, blobCache, file, base64);
  24443. pasteHtml(editor, `<img src="${ blobInfo.blobUri() }">`, false);
  24444. });
  24445. };
  24446. const isClipboardEvent = event => event.type === 'paste';
  24447. const readFilesAsDataUris = items => Promise.all(map$3(items, file => {
  24448. return blobToDataUri(file).then(uri => ({
  24449. file,
  24450. uri
  24451. }));
  24452. }));
  24453. const isImage = editor => {
  24454. const allowedExtensions = getAllowedImageFileTypes(editor);
  24455. return file => startsWith(file.type, 'image/') && exists(allowedExtensions, extension => {
  24456. return getImageMimeType(extension) === file.type;
  24457. });
  24458. };
  24459. const getImagesFromDataTransfer = (editor, dataTransfer) => {
  24460. const items = dataTransfer.items ? bind$3(from(dataTransfer.items), item => {
  24461. return item.kind === 'file' ? [item.getAsFile()] : [];
  24462. }) : [];
  24463. const files = dataTransfer.files ? from(dataTransfer.files) : [];
  24464. return filter$5(items.length > 0 ? items : files, isImage(editor));
  24465. };
  24466. const pasteImageData = (editor, e, rng) => {
  24467. const dataTransfer = isClipboardEvent(e) ? e.clipboardData : e.dataTransfer;
  24468. if (shouldPasteDataImages(editor) && dataTransfer) {
  24469. const images = getImagesFromDataTransfer(editor, dataTransfer);
  24470. if (images.length > 0) {
  24471. e.preventDefault();
  24472. readFilesAsDataUris(images).then(fileResults => {
  24473. if (rng) {
  24474. editor.selection.setRng(rng);
  24475. }
  24476. each$e(fileResults, result => {
  24477. pasteImage(editor, result);
  24478. });
  24479. });
  24480. return true;
  24481. }
  24482. }
  24483. return false;
  24484. };
  24485. const isBrokenAndroidClipboardEvent = e => {
  24486. var _a, _b;
  24487. return Env.os.isAndroid() && ((_b = (_a = e.clipboardData) === null || _a === void 0 ? void 0 : _a.items) === null || _b === void 0 ? void 0 : _b.length) === 0;
  24488. };
  24489. const isKeyboardPasteEvent = e => VK.metaKeyPressed(e) && e.keyCode === 86 || e.shiftKey && e.keyCode === 45;
  24490. const insertClipboardContent = (editor, clipboardContent, html, plainTextMode) => {
  24491. let content = trimHtml(html);
  24492. const isInternal = hasContentType(clipboardContent, internalHtmlMime()) || isMarked(html);
  24493. const isPlainTextHtml = !isInternal && isPlainText(content);
  24494. const isAbsoluteUrl$1 = isAbsoluteUrl(content);
  24495. if (isDefaultPasteBinContent(content) || !content.length || isPlainTextHtml && !isAbsoluteUrl$1) {
  24496. plainTextMode = true;
  24497. }
  24498. if (plainTextMode || isAbsoluteUrl$1) {
  24499. if (hasContentType(clipboardContent, 'text/plain') && isPlainTextHtml) {
  24500. content = clipboardContent['text/plain'];
  24501. } else {
  24502. content = innerText(content);
  24503. }
  24504. }
  24505. if (isDefaultPasteBinContent(content)) {
  24506. return;
  24507. }
  24508. if (plainTextMode) {
  24509. pasteText(editor, content);
  24510. } else {
  24511. pasteHtml(editor, content, isInternal);
  24512. }
  24513. };
  24514. const registerEventHandlers = (editor, pasteBin, pasteFormat) => {
  24515. let keyboardPastePlainTextState;
  24516. const getLastRng = () => pasteBin.getLastRng() || editor.selection.getRng();
  24517. editor.on('keydown', e => {
  24518. if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
  24519. keyboardPastePlainTextState = e.shiftKey && e.keyCode === 86;
  24520. }
  24521. });
  24522. editor.on('paste', e => {
  24523. if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
  24524. return;
  24525. }
  24526. const plainTextMode = pasteFormat.get() === 'text' || keyboardPastePlainTextState;
  24527. keyboardPastePlainTextState = false;
  24528. const clipboardContent = getDataTransferItems(e.clipboardData);
  24529. if (!hasHtmlOrText(clipboardContent) && pasteImageData(editor, e, getLastRng())) {
  24530. return;
  24531. }
  24532. if (hasContentType(clipboardContent, 'text/html')) {
  24533. e.preventDefault();
  24534. insertClipboardContent(editor, clipboardContent, clipboardContent['text/html'], plainTextMode);
  24535. } else {
  24536. pasteBin.create();
  24537. Delay.setEditorTimeout(editor, () => {
  24538. const html = pasteBin.getHtml();
  24539. pasteBin.remove();
  24540. insertClipboardContent(editor, clipboardContent, html, plainTextMode);
  24541. }, 0);
  24542. }
  24543. });
  24544. };
  24545. const registerDataImageFilter = editor => {
  24546. const isWebKitFakeUrl = src => startsWith(src, 'webkit-fake-url');
  24547. const isDataUri = src => startsWith(src, 'data:');
  24548. const isPasteInsert = args => {
  24549. var _a;
  24550. return ((_a = args.data) === null || _a === void 0 ? void 0 : _a.paste) === true;
  24551. };
  24552. editor.parser.addNodeFilter('img', (nodes, name, args) => {
  24553. if (!shouldPasteDataImages(editor) && isPasteInsert(args)) {
  24554. for (const node of nodes) {
  24555. const src = node.attr('src');
  24556. if (isString(src) && !node.attr('data-mce-object') && src !== Env.transparentSrc) {
  24557. if (isWebKitFakeUrl(src)) {
  24558. node.remove();
  24559. } else if (!shouldAllowHtmlDataUrls(editor) && isDataUri(src)) {
  24560. node.remove();
  24561. }
  24562. }
  24563. }
  24564. }
  24565. });
  24566. };
  24567. const registerEventsAndFilters = (editor, pasteBin, pasteFormat) => {
  24568. registerEventHandlers(editor, pasteBin, pasteFormat);
  24569. registerDataImageFilter(editor);
  24570. };
  24571. const togglePlainTextPaste = (editor, pasteFormat) => {
  24572. if (pasteFormat.get() === 'text') {
  24573. pasteFormat.set('html');
  24574. firePastePlainTextToggle(editor, false);
  24575. } else {
  24576. pasteFormat.set('text');
  24577. firePastePlainTextToggle(editor, true);
  24578. }
  24579. editor.focus();
  24580. };
  24581. const register$1 = (editor, pasteFormat) => {
  24582. editor.addCommand('mceTogglePlainTextPaste', () => {
  24583. togglePlainTextPaste(editor, pasteFormat);
  24584. });
  24585. editor.addCommand('mceInsertClipboardContent', (ui, value) => {
  24586. if (value.html) {
  24587. pasteHtml(editor, value.html, value.internal);
  24588. }
  24589. if (value.text) {
  24590. pasteText(editor, value.text);
  24591. }
  24592. });
  24593. };
  24594. const setHtml5Clipboard = (clipboardData, html, text) => {
  24595. if (clipboardData) {
  24596. try {
  24597. clipboardData.clearData();
  24598. clipboardData.setData('text/html', html);
  24599. clipboardData.setData('text/plain', text);
  24600. clipboardData.setData(internalHtmlMime(), html);
  24601. return true;
  24602. } catch (e) {
  24603. return false;
  24604. }
  24605. } else {
  24606. return false;
  24607. }
  24608. };
  24609. const setClipboardData = (evt, data, fallback, done) => {
  24610. if (setHtml5Clipboard(evt.clipboardData, data.html, data.text)) {
  24611. evt.preventDefault();
  24612. done();
  24613. } else {
  24614. fallback(data.html, done);
  24615. }
  24616. };
  24617. const fallback = editor => (html, done) => {
  24618. const {dom, selection} = editor;
  24619. const outer = dom.create('div', {
  24620. 'contenteditable': 'false',
  24621. 'data-mce-bogus': 'all'
  24622. });
  24623. const inner = dom.create('div', { contenteditable: 'true' }, html);
  24624. dom.setStyles(outer, {
  24625. position: 'fixed',
  24626. top: '0',
  24627. left: '-3000px',
  24628. width: '1000px',
  24629. overflow: 'hidden'
  24630. });
  24631. outer.appendChild(inner);
  24632. dom.add(editor.getBody(), outer);
  24633. const range = selection.getRng();
  24634. inner.focus();
  24635. const offscreenRange = dom.createRng();
  24636. offscreenRange.selectNodeContents(inner);
  24637. selection.setRng(offscreenRange);
  24638. Delay.setEditorTimeout(editor, () => {
  24639. selection.setRng(range);
  24640. dom.remove(outer);
  24641. done();
  24642. }, 0);
  24643. };
  24644. const getData = editor => ({
  24645. html: mark(editor.selection.getContent({ contextual: true })),
  24646. text: editor.selection.getContent({ format: 'text' })
  24647. });
  24648. const isTableSelection = editor => !!editor.dom.getParent(editor.selection.getStart(), 'td[data-mce-selected],th[data-mce-selected]', editor.getBody());
  24649. const hasSelectedContent = editor => !editor.selection.isCollapsed() || isTableSelection(editor);
  24650. const cut = editor => evt => {
  24651. if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
  24652. setClipboardData(evt, getData(editor), fallback(editor), () => {
  24653. if (Env.browser.isChromium() || Env.browser.isFirefox()) {
  24654. const rng = editor.selection.getRng();
  24655. Delay.setEditorTimeout(editor, () => {
  24656. editor.selection.setRng(rng);
  24657. editor.execCommand('Delete');
  24658. }, 0);
  24659. } else {
  24660. editor.execCommand('Delete');
  24661. }
  24662. });
  24663. }
  24664. };
  24665. const copy = editor => evt => {
  24666. if (!evt.isDefaultPrevented() && hasSelectedContent(editor)) {
  24667. setClipboardData(evt, getData(editor), fallback(editor), noop);
  24668. }
  24669. };
  24670. const register = editor => {
  24671. editor.on('cut', cut(editor));
  24672. editor.on('copy', copy(editor));
  24673. };
  24674. const getCaretRangeFromEvent = (editor, e) => {
  24675. var _a, _b;
  24676. return RangeUtils.getCaretRangeFromPoint((_a = e.clientX) !== null && _a !== void 0 ? _a : 0, (_b = e.clientY) !== null && _b !== void 0 ? _b : 0, editor.getDoc());
  24677. };
  24678. const isPlainTextFileUrl = content => {
  24679. const plainTextContent = content['text/plain'];
  24680. return plainTextContent ? plainTextContent.indexOf('file://') === 0 : false;
  24681. };
  24682. const setFocusedRange = (editor, rng) => {
  24683. editor.focus();
  24684. if (rng) {
  24685. editor.selection.setRng(rng);
  24686. }
  24687. };
  24688. const hasImage = dataTransfer => exists(dataTransfer.files, file => /^image\//.test(file.type));
  24689. const setup$a = (editor, draggingInternallyState) => {
  24690. if (shouldPasteBlockDrop(editor)) {
  24691. editor.on('dragend dragover draggesture dragdrop drop drag', e => {
  24692. e.preventDefault();
  24693. e.stopPropagation();
  24694. });
  24695. }
  24696. if (!shouldPasteDataImages(editor)) {
  24697. editor.on('drop', e => {
  24698. const dataTransfer = e.dataTransfer;
  24699. if (dataTransfer && hasImage(dataTransfer)) {
  24700. e.preventDefault();
  24701. }
  24702. });
  24703. }
  24704. editor.on('drop', e => {
  24705. if (e.isDefaultPrevented() || draggingInternallyState.get()) {
  24706. return;
  24707. }
  24708. const rng = getCaretRangeFromEvent(editor, e);
  24709. if (isNullable(rng)) {
  24710. return;
  24711. }
  24712. const dropContent = getDataTransferItems(e.dataTransfer);
  24713. const internal = hasContentType(dropContent, internalHtmlMime());
  24714. if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(editor, e, rng)) {
  24715. return;
  24716. }
  24717. const internalContent = dropContent[internalHtmlMime()];
  24718. const content = internalContent || dropContent['text/html'] || dropContent['text/plain'];
  24719. if (content) {
  24720. e.preventDefault();
  24721. Delay.setEditorTimeout(editor, () => {
  24722. editor.undoManager.transact(() => {
  24723. if (internalContent) {
  24724. editor.execCommand('Delete');
  24725. }
  24726. setFocusedRange(editor, rng);
  24727. const trimmedContent = trimHtml(content);
  24728. if (dropContent['text/html']) {
  24729. pasteHtml(editor, trimmedContent, internal);
  24730. } else {
  24731. pasteText(editor, trimmedContent);
  24732. }
  24733. });
  24734. });
  24735. }
  24736. });
  24737. editor.on('dragstart', _e => {
  24738. draggingInternallyState.set(true);
  24739. });
  24740. editor.on('dragover dragend', e => {
  24741. if (shouldPasteDataImages(editor) && !draggingInternallyState.get()) {
  24742. e.preventDefault();
  24743. setFocusedRange(editor, getCaretRangeFromEvent(editor, e));
  24744. }
  24745. if (e.type === 'dragend') {
  24746. draggingInternallyState.set(false);
  24747. }
  24748. });
  24749. };
  24750. const setup$9 = editor => {
  24751. const processEvent = f => e => {
  24752. f(editor, e);
  24753. };
  24754. const preProcess = getPastePreProcess(editor);
  24755. if (isFunction(preProcess)) {
  24756. editor.on('PastePreProcess', processEvent(preProcess));
  24757. }
  24758. const postProcess = getPastePostProcess(editor);
  24759. if (isFunction(postProcess)) {
  24760. editor.on('PastePostProcess', processEvent(postProcess));
  24761. }
  24762. };
  24763. const addPreProcessFilter = (editor, filterFunc) => {
  24764. editor.on('PastePreProcess', e => {
  24765. e.content = filterFunc(editor, e.content, e.internal);
  24766. });
  24767. };
  24768. const rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi;
  24769. const rgbToHex = value => Tools.trim(value).replace(rgbRegExp, rgbaToHexString).toLowerCase();
  24770. const removeWebKitStyles = (editor, content, internal) => {
  24771. const webKitStylesOption = getPasteWebkitStyles(editor);
  24772. if (internal || webKitStylesOption === 'all' || !shouldPasteRemoveWebKitStyles(editor)) {
  24773. return content;
  24774. }
  24775. const webKitStyles = webKitStylesOption ? webKitStylesOption.split(/[, ]/) : [];
  24776. if (webKitStyles && webKitStylesOption !== 'none') {
  24777. const dom = editor.dom, node = editor.selection.getNode();
  24778. content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, (all, before, value, after) => {
  24779. const inputStyles = dom.parseStyle(dom.decode(value));
  24780. const outputStyles = {};
  24781. for (let i = 0; i < webKitStyles.length; i++) {
  24782. const inputValue = inputStyles[webKitStyles[i]];
  24783. let compareInput = inputValue;
  24784. let currentValue = dom.getStyle(node, webKitStyles[i], true);
  24785. if (/color/.test(webKitStyles[i])) {
  24786. compareInput = rgbToHex(compareInput);
  24787. currentValue = rgbToHex(currentValue);
  24788. }
  24789. if (currentValue !== compareInput) {
  24790. outputStyles[webKitStyles[i]] = inputValue;
  24791. }
  24792. }
  24793. const outputStyle = dom.serializeStyle(outputStyles, 'span');
  24794. if (outputStyle) {
  24795. return before + ' style="' + outputStyle + '"' + after;
  24796. }
  24797. return before + after;
  24798. });
  24799. } else {
  24800. content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
  24801. }
  24802. content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, (all, before, value, after) => {
  24803. return before + ' style="' + value + '"' + after;
  24804. });
  24805. return content;
  24806. };
  24807. const setup$8 = editor => {
  24808. if (Env.browser.isChromium() || Env.browser.isSafari()) {
  24809. addPreProcessFilter(editor, removeWebKitStyles);
  24810. }
  24811. };
  24812. const setup$7 = editor => {
  24813. const draggingInternallyState = Cell(false);
  24814. const pasteFormat = Cell(isPasteAsTextEnabled(editor) ? 'text' : 'html');
  24815. const pasteBin = PasteBin(editor);
  24816. setup$8(editor);
  24817. register$1(editor, pasteFormat);
  24818. setup$9(editor);
  24819. editor.on('PreInit', () => {
  24820. register(editor);
  24821. setup$a(editor, draggingInternallyState);
  24822. registerEventsAndFilters(editor, pasteBin, pasteFormat);
  24823. });
  24824. };
  24825. const preventSummaryToggle = editor => {
  24826. editor.on('click', e => {
  24827. if (editor.dom.getParent(e.target, 'details')) {
  24828. e.preventDefault();
  24829. }
  24830. });
  24831. };
  24832. const filterDetails = editor => {
  24833. editor.parser.addNodeFilter('details', elms => {
  24834. each$e(elms, details => {
  24835. details.attr('data-mce-open', details.attr('open'));
  24836. details.attr('open', 'open');
  24837. });
  24838. });
  24839. editor.serializer.addNodeFilter('details', elms => {
  24840. each$e(elms, details => {
  24841. const open = details.attr('data-mce-open');
  24842. details.attr('open', isString(open) ? open : null);
  24843. details.attr('data-mce-open', null);
  24844. });
  24845. });
  24846. };
  24847. const setup$6 = editor => {
  24848. preventSummaryToggle(editor);
  24849. filterDetails(editor);
  24850. };
  24851. const isBr = isBr$6;
  24852. const isText = isText$a;
  24853. const isContentEditableFalse$2 = elm => isContentEditableFalse$a(elm.dom);
  24854. const isContentEditableTrue = elm => isContentEditableTrue$3(elm.dom);
  24855. const isRoot = rootNode => elm => eq(SugarElement.fromDom(rootNode), elm);
  24856. const getClosestScope = (node, rootNode) => closest$4(SugarElement.fromDom(node), elm => isContentEditableTrue(elm) || isBlock$2(elm), isRoot(rootNode)).getOr(SugarElement.fromDom(rootNode)).dom;
  24857. const getClosestCef = (node, rootNode) => closest$4(SugarElement.fromDom(node), isContentEditableFalse$2, isRoot(rootNode));
  24858. const findEdgeCaretCandidate = (startNode, scope, forward) => {
  24859. const walker = new DomTreeWalker(startNode, scope);
  24860. const next = forward ? walker.next.bind(walker) : walker.prev.bind(walker);
  24861. let result = startNode;
  24862. for (let current = forward ? startNode : next(); current && !isBr(current); current = next()) {
  24863. if (isCaretCandidate$3(current)) {
  24864. result = current;
  24865. }
  24866. }
  24867. return result;
  24868. };
  24869. const findClosestBlockRange = (startRng, rootNode) => {
  24870. const startPos = CaretPosition.fromRangeStart(startRng);
  24871. const clickNode = startPos.getNode();
  24872. const scope = getClosestScope(clickNode, rootNode);
  24873. const startNode = findEdgeCaretCandidate(clickNode, scope, false);
  24874. const endNode = findEdgeCaretCandidate(clickNode, scope, true);
  24875. const rng = document.createRange();
  24876. getClosestCef(startNode, scope).fold(() => {
  24877. if (isText(startNode)) {
  24878. rng.setStart(startNode, 0);
  24879. } else {
  24880. rng.setStartBefore(startNode);
  24881. }
  24882. }, cef => rng.setStartBefore(cef.dom));
  24883. getClosestCef(endNode, scope).fold(() => {
  24884. if (isText(endNode)) {
  24885. rng.setEnd(endNode, endNode.data.length);
  24886. } else {
  24887. rng.setEndAfter(endNode);
  24888. }
  24889. }, cef => rng.setEndAfter(cef.dom));
  24890. return rng;
  24891. };
  24892. const onTripleClickSelect = editor => {
  24893. const rng = findClosestBlockRange(editor.selection.getRng(), editor.getBody());
  24894. editor.selection.setRng(normalize(rng));
  24895. };
  24896. const setup$5 = editor => {
  24897. editor.on('mousedown', e => {
  24898. if (e.detail >= 3) {
  24899. e.preventDefault();
  24900. onTripleClickSelect(editor);
  24901. }
  24902. });
  24903. };
  24904. var FakeCaretPosition;
  24905. (function (FakeCaretPosition) {
  24906. FakeCaretPosition['Before'] = 'before';
  24907. FakeCaretPosition['After'] = 'after';
  24908. }(FakeCaretPosition || (FakeCaretPosition = {})));
  24909. const distanceToRectLeft = (clientRect, clientX) => Math.abs(clientRect.left - clientX);
  24910. const distanceToRectRight = (clientRect, clientX) => Math.abs(clientRect.right - clientX);
  24911. const isInsideY = (clientY, clientRect) => clientY >= clientRect.top && clientY <= clientRect.bottom;
  24912. const collidesY = (r1, r2) => r1.top < r2.bottom && r1.bottom > r2.top;
  24913. const isOverlapping = (r1, r2) => {
  24914. const overlap = overlapY(r1, r2) / Math.min(r1.height, r2.height);
  24915. return collidesY(r1, r2) && overlap > 0.5;
  24916. };
  24917. const splitRectsPerAxis = (rects, y) => {
  24918. const intersectingRects = filter$5(rects, rect => isInsideY(y, rect));
  24919. return boundingClientRectFromRects(intersectingRects).fold(() => [
  24920. [],
  24921. rects
  24922. ], boundingRect => {
  24923. const {
  24924. pass: horizontal,
  24925. fail: vertical
  24926. } = partition$2(rects, rect => isOverlapping(rect, boundingRect));
  24927. return [
  24928. horizontal,
  24929. vertical
  24930. ];
  24931. });
  24932. };
  24933. const clientInfo = (rect, clientX) => {
  24934. return {
  24935. node: rect.node,
  24936. position: distanceToRectLeft(rect, clientX) < distanceToRectRight(rect, clientX) ? FakeCaretPosition.Before : FakeCaretPosition.After
  24937. };
  24938. };
  24939. const horizontalDistance = (rect, x, _y) => x > rect.left && x < rect.right ? 0 : Math.min(Math.abs(rect.left - x), Math.abs(rect.right - x));
  24940. const closestChildCaretCandidateNodeRect = (children, clientX, clientY) => {
  24941. const caretCandidateRect = rect => {
  24942. if (isCaretCandidate$3(rect.node)) {
  24943. return Optional.some(rect);
  24944. } else if (isElement$6(rect.node)) {
  24945. return closestChildCaretCandidateNodeRect(from(rect.node.childNodes), clientX, clientY);
  24946. } else {
  24947. return Optional.none();
  24948. }
  24949. };
  24950. const getClosestTextNode = (rects, distance) => {
  24951. if (rects.length >= 2) {
  24952. const r1 = caretCandidateRect(rects[0]).getOr(rects[0]);
  24953. const r2 = caretCandidateRect(rects[1]).getOr(rects[1]);
  24954. const deltaDistance = Math.abs(distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
  24955. if (deltaDistance < 2) {
  24956. if (isText$a(r1.node)) {
  24957. return Optional.some(r1);
  24958. } else if (isText$a(r2.node)) {
  24959. return Optional.some(r2);
  24960. }
  24961. }
  24962. }
  24963. return Optional.none();
  24964. };
  24965. const findClosestCaretCandidateNodeRect = (rects, distance) => {
  24966. const sortedRects = sort(rects, (r1, r2) => distance(r1, clientX, clientY) - distance(r2, clientX, clientY));
  24967. return getClosestTextNode(sortedRects, distance).orThunk(() => findMap(sortedRects, caretCandidateRect));
  24968. };
  24969. const [horizontalRects, verticalRects] = splitRectsPerAxis(getClientRects(children), clientY);
  24970. const {
  24971. pass: above,
  24972. fail: below
  24973. } = partition$2(verticalRects, rect => rect.top < clientY);
  24974. return findClosestCaretCandidateNodeRect(horizontalRects, horizontalDistance).orThunk(() => findClosestCaretCandidateNodeRect(below, distanceToRectEdgeFromXY)).orThunk(() => findClosestCaretCandidateNodeRect(above, distanceToRectEdgeFromXY));
  24975. };
  24976. const traverseUp = (rootElm, scope, clientX, clientY) => {
  24977. const helper = (scope, prevScope) => {
  24978. const isDragGhostContainer = node => isElement$6(node) && node.classList.contains('mce-drag-container');
  24979. const childNodesWithoutGhost = filter$5(scope.dom.childNodes, not(isDragGhostContainer));
  24980. return prevScope.fold(() => closestChildCaretCandidateNodeRect(childNodesWithoutGhost, clientX, clientY), prevScope => {
  24981. const uncheckedChildren = filter$5(childNodesWithoutGhost, node => node !== prevScope.dom);
  24982. return closestChildCaretCandidateNodeRect(uncheckedChildren, clientX, clientY);
  24983. }).orThunk(() => {
  24984. const parent = eq(scope, rootElm) ? Optional.none() : parentElement(scope);
  24985. return parent.bind(newScope => helper(newScope, Optional.some(scope)));
  24986. });
  24987. };
  24988. return helper(scope, Optional.none());
  24989. };
  24990. const closestCaretCandidateNodeRect = (root, clientX, clientY) => {
  24991. const rootElm = SugarElement.fromDom(root);
  24992. const ownerDoc = documentOrOwner(rootElm);
  24993. const elementAtPoint = SugarElement.fromPoint(ownerDoc, clientX, clientY).filter(elm => contains(rootElm, elm));
  24994. const element = elementAtPoint.getOr(rootElm);
  24995. return traverseUp(rootElm, element, clientX, clientY);
  24996. };
  24997. const closestFakeCaretCandidate = (root, clientX, clientY) => closestCaretCandidateNodeRect(root, clientX, clientY).filter(rect => isFakeCaretTarget(rect.node)).map(rect => clientInfo(rect, clientX));
  24998. const getAbsolutePosition = elm => {
  24999. var _a, _b;
  25000. const clientRect = elm.getBoundingClientRect();
  25001. const doc = elm.ownerDocument;
  25002. const docElem = doc.documentElement;
  25003. const win = doc.defaultView;
  25004. return {
  25005. top: clientRect.top + ((_a = win === null || win === void 0 ? void 0 : win.scrollY) !== null && _a !== void 0 ? _a : 0) - docElem.clientTop,
  25006. left: clientRect.left + ((_b = win === null || win === void 0 ? void 0 : win.scrollX) !== null && _b !== void 0 ? _b : 0) - docElem.clientLeft
  25007. };
  25008. };
  25009. const getBodyPosition = editor => editor.inline ? getAbsolutePosition(editor.getBody()) : {
  25010. left: 0,
  25011. top: 0
  25012. };
  25013. const getScrollPosition = editor => {
  25014. const body = editor.getBody();
  25015. return editor.inline ? {
  25016. left: body.scrollLeft,
  25017. top: body.scrollTop
  25018. } : {
  25019. left: 0,
  25020. top: 0
  25021. };
  25022. };
  25023. const getBodyScroll = editor => {
  25024. const body = editor.getBody(), docElm = editor.getDoc().documentElement;
  25025. const inlineScroll = {
  25026. left: body.scrollLeft,
  25027. top: body.scrollTop
  25028. };
  25029. const iframeScroll = {
  25030. left: body.scrollLeft || docElm.scrollLeft,
  25031. top: body.scrollTop || docElm.scrollTop
  25032. };
  25033. return editor.inline ? inlineScroll : iframeScroll;
  25034. };
  25035. const getMousePosition = (editor, event) => {
  25036. if (event.target.ownerDocument !== editor.getDoc()) {
  25037. const iframePosition = getAbsolutePosition(editor.getContentAreaContainer());
  25038. const scrollPosition = getBodyScroll(editor);
  25039. return {
  25040. left: event.pageX - iframePosition.left + scrollPosition.left,
  25041. top: event.pageY - iframePosition.top + scrollPosition.top
  25042. };
  25043. }
  25044. return {
  25045. left: event.pageX,
  25046. top: event.pageY
  25047. };
  25048. };
  25049. const calculatePosition = (bodyPosition, scrollPosition, mousePosition) => ({
  25050. pageX: mousePosition.left - bodyPosition.left + scrollPosition.left,
  25051. pageY: mousePosition.top - bodyPosition.top + scrollPosition.top
  25052. });
  25053. const calc = (editor, event) => calculatePosition(getBodyPosition(editor), getScrollPosition(editor), getMousePosition(editor, event));
  25054. const scrollPixelsPerInterval = 32;
  25055. const scrollIntervalValue = 100;
  25056. const mouseRangeToTriggerScrollInsideEditor = 8;
  25057. const mouseRangeToTriggerScrollOutsideEditor = 16;
  25058. const isContentEditableFalse$1 = isContentEditableFalse$a;
  25059. const isContentEditable = or(isContentEditableFalse$1, isContentEditableTrue$3);
  25060. const isDraggable = (rootElm, elm) => isContentEditableFalse$1(elm) && elm !== rootElm;
  25061. const isValidDropTarget = (editor, targetElement, dragElement) => {
  25062. if (isNullable(targetElement)) {
  25063. return false;
  25064. } else if (targetElement === dragElement || editor.dom.isChildOf(targetElement, dragElement)) {
  25065. return false;
  25066. } else {
  25067. return !isContentEditableFalse$1(targetElement);
  25068. }
  25069. };
  25070. const cloneElement = elm => {
  25071. const cloneElm = elm.cloneNode(true);
  25072. cloneElm.removeAttribute('data-mce-selected');
  25073. return cloneElm;
  25074. };
  25075. const createGhost = (editor, elm, width, height) => {
  25076. const dom = editor.dom;
  25077. const clonedElm = elm.cloneNode(true);
  25078. dom.setStyles(clonedElm, {
  25079. width,
  25080. height
  25081. });
  25082. dom.setAttrib(clonedElm, 'data-mce-selected', null);
  25083. const ghostElm = dom.create('div', {
  25084. 'class': 'mce-drag-container',
  25085. 'data-mce-bogus': 'all',
  25086. 'unselectable': 'on',
  25087. 'contenteditable': 'false'
  25088. });
  25089. dom.setStyles(ghostElm, {
  25090. position: 'absolute',
  25091. opacity: 0.5,
  25092. overflow: 'hidden',
  25093. border: 0,
  25094. padding: 0,
  25095. margin: 0,
  25096. width,
  25097. height
  25098. });
  25099. dom.setStyles(clonedElm, {
  25100. margin: 0,
  25101. boxSizing: 'border-box'
  25102. });
  25103. ghostElm.appendChild(clonedElm);
  25104. return ghostElm;
  25105. };
  25106. const appendGhostToBody = (ghostElm, bodyElm) => {
  25107. if (ghostElm.parentNode !== bodyElm) {
  25108. bodyElm.appendChild(ghostElm);
  25109. }
  25110. };
  25111. const scrollEditor = (direction, amount) => win => () => {
  25112. const current = direction === 'left' ? win.scrollX : win.scrollY;
  25113. win.scroll({
  25114. [direction]: current + amount,
  25115. behavior: 'smooth'
  25116. });
  25117. };
  25118. const scrollLeft = scrollEditor('left', -scrollPixelsPerInterval);
  25119. const scrollRight = scrollEditor('left', scrollPixelsPerInterval);
  25120. const scrollUp = scrollEditor('top', -scrollPixelsPerInterval);
  25121. const scrollDown = scrollEditor('top', scrollPixelsPerInterval);
  25122. const moveGhost = (ghostElm, position, width, height, maxX, maxY, mouseY, mouseX, contentAreaContainer, win, state, mouseEventOriginatedFromWithinTheEditor) => {
  25123. let overflowX = 0, overflowY = 0;
  25124. ghostElm.style.left = position.pageX + 'px';
  25125. ghostElm.style.top = position.pageY + 'px';
  25126. if (position.pageX + width > maxX) {
  25127. overflowX = position.pageX + width - maxX;
  25128. }
  25129. if (position.pageY + height > maxY) {
  25130. overflowY = position.pageY + height - maxY;
  25131. }
  25132. ghostElm.style.width = width - overflowX + 'px';
  25133. ghostElm.style.height = height - overflowY + 'px';
  25134. const clientHeight = contentAreaContainer.clientHeight;
  25135. const clientWidth = contentAreaContainer.clientWidth;
  25136. const outerMouseY = mouseY + contentAreaContainer.getBoundingClientRect().top;
  25137. const outerMouseX = mouseX + contentAreaContainer.getBoundingClientRect().left;
  25138. state.on(state => {
  25139. state.intervalId.clear();
  25140. if (state.dragging && mouseEventOriginatedFromWithinTheEditor) {
  25141. if (mouseY + mouseRangeToTriggerScrollInsideEditor >= clientHeight) {
  25142. state.intervalId.set(scrollDown(win));
  25143. } else if (mouseY - mouseRangeToTriggerScrollInsideEditor <= 0) {
  25144. state.intervalId.set(scrollUp(win));
  25145. } else if (mouseX + mouseRangeToTriggerScrollInsideEditor >= clientWidth) {
  25146. state.intervalId.set(scrollRight(win));
  25147. } else if (mouseX - mouseRangeToTriggerScrollInsideEditor <= 0) {
  25148. state.intervalId.set(scrollLeft(win));
  25149. } else if (outerMouseY + mouseRangeToTriggerScrollOutsideEditor >= window.innerHeight) {
  25150. state.intervalId.set(scrollDown(window));
  25151. } else if (outerMouseY - mouseRangeToTriggerScrollOutsideEditor <= 0) {
  25152. state.intervalId.set(scrollUp(window));
  25153. } else if (outerMouseX + mouseRangeToTriggerScrollOutsideEditor >= window.innerWidth) {
  25154. state.intervalId.set(scrollRight(window));
  25155. } else if (outerMouseX - mouseRangeToTriggerScrollOutsideEditor <= 0) {
  25156. state.intervalId.set(scrollLeft(window));
  25157. }
  25158. }
  25159. });
  25160. };
  25161. const removeElement = elm => {
  25162. if (elm && elm.parentNode) {
  25163. elm.parentNode.removeChild(elm);
  25164. }
  25165. };
  25166. const isLeftMouseButtonPressed = e => e.button === 0;
  25167. const applyRelPos = (state, position) => ({
  25168. pageX: position.pageX - state.relX,
  25169. pageY: position.pageY + 5
  25170. });
  25171. const start = (state, editor) => e => {
  25172. if (isLeftMouseButtonPressed(e)) {
  25173. const ceElm = find$2(editor.dom.getParents(e.target), isContentEditable).getOr(null);
  25174. if (isNonNullable(ceElm) && isDraggable(editor.getBody(), ceElm)) {
  25175. const elmPos = editor.dom.getPos(ceElm);
  25176. const bodyElm = editor.getBody();
  25177. const docElm = editor.getDoc().documentElement;
  25178. state.set({
  25179. element: ceElm,
  25180. dragging: false,
  25181. screenX: e.screenX,
  25182. screenY: e.screenY,
  25183. maxX: (editor.inline ? bodyElm.scrollWidth : docElm.offsetWidth) - 2,
  25184. maxY: (editor.inline ? bodyElm.scrollHeight : docElm.offsetHeight) - 2,
  25185. relX: e.pageX - elmPos.x,
  25186. relY: e.pageY - elmPos.y,
  25187. width: ceElm.offsetWidth,
  25188. height: ceElm.offsetHeight,
  25189. ghost: createGhost(editor, ceElm, ceElm.offsetWidth, ceElm.offsetHeight),
  25190. intervalId: repeatable(scrollIntervalValue)
  25191. });
  25192. }
  25193. }
  25194. };
  25195. const move = (state, editor) => {
  25196. const throttledPlaceCaretAt = first$1((clientX, clientY) => {
  25197. editor._selectionOverrides.hideFakeCaret();
  25198. closestFakeCaretCandidate(editor.getBody(), clientX, clientY).fold(() => editor.selection.placeCaretAt(clientX, clientY), caretInfo => {
  25199. const range = editor._selectionOverrides.showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
  25200. if (range) {
  25201. editor.selection.setRng(range);
  25202. } else {
  25203. editor.selection.placeCaretAt(clientX, clientY);
  25204. }
  25205. });
  25206. }, 0);
  25207. editor.on('remove', throttledPlaceCaretAt.cancel);
  25208. const state_ = state;
  25209. return e => state.on(state => {
  25210. const movement = Math.max(Math.abs(e.screenX - state.screenX), Math.abs(e.screenY - state.screenY));
  25211. if (!state.dragging && movement > 10) {
  25212. const args = editor.dispatch('dragstart', { target: state.element });
  25213. if (args.isDefaultPrevented()) {
  25214. return;
  25215. }
  25216. state.dragging = true;
  25217. editor.focus();
  25218. }
  25219. if (state.dragging) {
  25220. const mouseEventOriginatedFromWithinTheEditor = e.currentTarget === editor.getDoc().documentElement;
  25221. const targetPos = applyRelPos(state, calc(editor, e));
  25222. appendGhostToBody(state.ghost, editor.getBody());
  25223. moveGhost(state.ghost, targetPos, state.width, state.height, state.maxX, state.maxY, e.clientY, e.clientX, editor.getContentAreaContainer(), editor.getWin(), state_, mouseEventOriginatedFromWithinTheEditor);
  25224. throttledPlaceCaretAt.throttle(e.clientX, e.clientY);
  25225. }
  25226. });
  25227. };
  25228. const getRawTarget = selection => {
  25229. const sel = selection.getSel();
  25230. if (isNonNullable(sel)) {
  25231. const rng = sel.getRangeAt(0);
  25232. const startContainer = rng.startContainer;
  25233. return isText$a(startContainer) ? startContainer.parentNode : startContainer;
  25234. } else {
  25235. return null;
  25236. }
  25237. };
  25238. const drop = (state, editor) => e => {
  25239. state.on(state => {
  25240. state.intervalId.clear();
  25241. if (state.dragging) {
  25242. if (isValidDropTarget(editor, getRawTarget(editor.selection), state.element)) {
  25243. const targetClone = cloneElement(state.element);
  25244. const args = editor.dispatch('drop', {
  25245. clientX: e.clientX,
  25246. clientY: e.clientY
  25247. });
  25248. if (!args.isDefaultPrevented()) {
  25249. editor.undoManager.transact(() => {
  25250. removeElement(state.element);
  25251. editor.insertContent(editor.dom.getOuterHTML(targetClone));
  25252. editor._selectionOverrides.hideFakeCaret();
  25253. });
  25254. }
  25255. }
  25256. editor.dispatch('dragend');
  25257. }
  25258. });
  25259. removeDragState(state);
  25260. };
  25261. const stop = (state, editor) => () => {
  25262. state.on(state => {
  25263. state.intervalId.clear();
  25264. if (state.dragging) {
  25265. editor.dispatch('dragend');
  25266. }
  25267. });
  25268. removeDragState(state);
  25269. };
  25270. const removeDragState = state => {
  25271. state.on(state => {
  25272. state.intervalId.clear();
  25273. removeElement(state.ghost);
  25274. });
  25275. state.clear();
  25276. };
  25277. const bindFakeDragEvents = editor => {
  25278. const state = value$2();
  25279. const pageDom = DOMUtils.DOM;
  25280. const rootDocument = document;
  25281. const dragStartHandler = start(state, editor);
  25282. const dragHandler = move(state, editor);
  25283. const dropHandler = drop(state, editor);
  25284. const dragEndHandler = stop(state, editor);
  25285. editor.on('mousedown', dragStartHandler);
  25286. editor.on('mousemove', dragHandler);
  25287. editor.on('mouseup', dropHandler);
  25288. pageDom.bind(rootDocument, 'mousemove', dragHandler);
  25289. pageDom.bind(rootDocument, 'mouseup', dragEndHandler);
  25290. editor.on('remove', () => {
  25291. pageDom.unbind(rootDocument, 'mousemove', dragHandler);
  25292. pageDom.unbind(rootDocument, 'mouseup', dragEndHandler);
  25293. });
  25294. editor.on('keydown', e => {
  25295. if (e.keyCode === VK.ESC) {
  25296. dragEndHandler();
  25297. }
  25298. });
  25299. };
  25300. const blockUnsupportedFileDrop = editor => {
  25301. const preventFileDrop = e => {
  25302. if (!e.isDefaultPrevented()) {
  25303. const dataTransfer = e.dataTransfer;
  25304. if (dataTransfer && (contains$2(dataTransfer.types, 'Files') || dataTransfer.files.length > 0)) {
  25305. e.preventDefault();
  25306. if (e.type === 'drop') {
  25307. displayError(editor, 'Dropped file type is not supported');
  25308. }
  25309. }
  25310. }
  25311. };
  25312. const preventFileDropIfUIElement = e => {
  25313. if (isUIElement(editor, e.target)) {
  25314. preventFileDrop(e);
  25315. }
  25316. };
  25317. const setup = () => {
  25318. const pageDom = DOMUtils.DOM;
  25319. const dom = editor.dom;
  25320. const doc = document;
  25321. const editorRoot = editor.inline ? editor.getBody() : editor.getDoc();
  25322. const eventNames = [
  25323. 'drop',
  25324. 'dragover'
  25325. ];
  25326. each$e(eventNames, name => {
  25327. pageDom.bind(doc, name, preventFileDropIfUIElement);
  25328. dom.bind(editorRoot, name, preventFileDrop);
  25329. });
  25330. editor.on('remove', () => {
  25331. each$e(eventNames, name => {
  25332. pageDom.unbind(doc, name, preventFileDropIfUIElement);
  25333. dom.unbind(editorRoot, name, preventFileDrop);
  25334. });
  25335. });
  25336. };
  25337. editor.on('init', () => {
  25338. Delay.setEditorTimeout(editor, setup, 0);
  25339. });
  25340. };
  25341. const init$2 = editor => {
  25342. bindFakeDragEvents(editor);
  25343. if (shouldBlockUnsupportedDrop(editor)) {
  25344. blockUnsupportedFileDrop(editor);
  25345. }
  25346. };
  25347. const setup$4 = editor => {
  25348. const renderFocusCaret = first$1(() => {
  25349. if (!editor.removed && editor.getBody().contains(document.activeElement)) {
  25350. const rng = editor.selection.getRng();
  25351. if (rng.collapsed) {
  25352. const caretRange = renderRangeCaret(editor, rng, false);
  25353. editor.selection.setRng(caretRange);
  25354. }
  25355. }
  25356. }, 0);
  25357. editor.on('focus', () => {
  25358. renderFocusCaret.throttle();
  25359. });
  25360. editor.on('blur', () => {
  25361. renderFocusCaret.cancel();
  25362. });
  25363. };
  25364. const setup$3 = editor => {
  25365. editor.on('init', () => {
  25366. editor.on('focusin', e => {
  25367. const target = e.target;
  25368. if (isMedia$2(target)) {
  25369. const ceRoot = getContentEditableRoot$1(editor.getBody(), target);
  25370. const node = isContentEditableFalse$a(ceRoot) ? ceRoot : target;
  25371. if (editor.selection.getNode() !== node) {
  25372. selectNode(editor, node).each(rng => editor.selection.setRng(rng));
  25373. }
  25374. }
  25375. });
  25376. });
  25377. };
  25378. const isContentEditableFalse = isContentEditableFalse$a;
  25379. const getContentEditableRoot = (editor, node) => getContentEditableRoot$1(editor.getBody(), node);
  25380. const SelectionOverrides = editor => {
  25381. const selection = editor.selection, dom = editor.dom;
  25382. const rootNode = editor.getBody();
  25383. const fakeCaret = FakeCaret(editor, rootNode, dom.isBlock, () => hasFocus(editor));
  25384. const realSelectionId = 'sel-' + dom.uniqueId();
  25385. const elementSelectionAttr = 'data-mce-selected';
  25386. let selectedElement;
  25387. const isFakeSelectionElement = node => isNonNullable(node) && dom.hasClass(node, 'mce-offscreen-selection');
  25388. const isFakeSelectionTargetElement = node => node !== rootNode && (isContentEditableFalse(node) || isMedia$2(node)) && dom.isChildOf(node, rootNode);
  25389. const setRange = range => {
  25390. if (range) {
  25391. selection.setRng(range);
  25392. }
  25393. };
  25394. const showCaret = (direction, node, before, scrollIntoView = true) => {
  25395. const e = editor.dispatch('ShowCaret', {
  25396. target: node,
  25397. direction,
  25398. before
  25399. });
  25400. if (e.isDefaultPrevented()) {
  25401. return null;
  25402. }
  25403. if (scrollIntoView) {
  25404. selection.scrollIntoView(node, direction === -1);
  25405. }
  25406. return fakeCaret.show(before, node);
  25407. };
  25408. const showBlockCaretContainer = blockCaretContainer => {
  25409. if (blockCaretContainer.hasAttribute('data-mce-caret')) {
  25410. showCaretContainerBlock(blockCaretContainer);
  25411. selection.scrollIntoView(blockCaretContainer);
  25412. }
  25413. };
  25414. const registerEvents = () => {
  25415. editor.on('click', e => {
  25416. const contentEditableRoot = getContentEditableRoot(editor, e.target);
  25417. if (contentEditableRoot) {
  25418. if (isContentEditableFalse(contentEditableRoot)) {
  25419. e.preventDefault();
  25420. editor.focus();
  25421. }
  25422. }
  25423. });
  25424. editor.on('blur NewBlock', removeElementSelection);
  25425. editor.on('ResizeWindow FullscreenStateChanged', fakeCaret.reposition);
  25426. editor.on('tap', e => {
  25427. const targetElm = e.target;
  25428. const contentEditableRoot = getContentEditableRoot(editor, targetElm);
  25429. if (isContentEditableFalse(contentEditableRoot)) {
  25430. e.preventDefault();
  25431. selectNode(editor, contentEditableRoot).each(setElementSelection);
  25432. } else if (isFakeSelectionTargetElement(targetElm)) {
  25433. selectNode(editor, targetElm).each(setElementSelection);
  25434. }
  25435. }, true);
  25436. editor.on('mousedown', e => {
  25437. const targetElm = e.target;
  25438. if (targetElm !== rootNode && targetElm.nodeName !== 'HTML' && !dom.isChildOf(targetElm, rootNode)) {
  25439. return;
  25440. }
  25441. if (!isXYInContentArea(editor, e.clientX, e.clientY)) {
  25442. return;
  25443. }
  25444. removeElementSelection();
  25445. hideFakeCaret();
  25446. const closestContentEditable = getContentEditableRoot(editor, targetElm);
  25447. if (isContentEditableFalse(closestContentEditable)) {
  25448. e.preventDefault();
  25449. selectNode(editor, closestContentEditable).each(setElementSelection);
  25450. } else {
  25451. closestFakeCaretCandidate(rootNode, e.clientX, e.clientY).each(caretInfo => {
  25452. e.preventDefault();
  25453. const range = showCaret(1, caretInfo.node, caretInfo.position === FakeCaretPosition.Before, false);
  25454. setRange(range);
  25455. if (isElement$6(closestContentEditable)) {
  25456. closestContentEditable.focus();
  25457. } else {
  25458. editor.getBody().focus();
  25459. }
  25460. });
  25461. }
  25462. });
  25463. editor.on('keypress', e => {
  25464. if (VK.modifierPressed(e)) {
  25465. return;
  25466. }
  25467. if (isContentEditableFalse(selection.getNode())) {
  25468. e.preventDefault();
  25469. }
  25470. });
  25471. editor.on('GetSelectionRange', e => {
  25472. let rng = e.range;
  25473. if (selectedElement) {
  25474. if (!selectedElement.parentNode) {
  25475. selectedElement = null;
  25476. return;
  25477. }
  25478. rng = rng.cloneRange();
  25479. rng.selectNode(selectedElement);
  25480. e.range = rng;
  25481. }
  25482. });
  25483. editor.on('SetSelectionRange', e => {
  25484. e.range = normalizeVoidElementSelection(e.range);
  25485. const rng = setElementSelection(e.range, e.forward);
  25486. if (rng) {
  25487. e.range = rng;
  25488. }
  25489. });
  25490. const isPasteBin = node => isElement$6(node) && node.id === 'mcepastebin';
  25491. editor.on('AfterSetSelectionRange', e => {
  25492. const rng = e.range;
  25493. const parent = rng.startContainer.parentElement;
  25494. if (!isRangeInCaretContainer(rng) && !isPasteBin(parent)) {
  25495. hideFakeCaret();
  25496. }
  25497. if (!isFakeSelectionElement(parent)) {
  25498. removeElementSelection();
  25499. }
  25500. });
  25501. init$2(editor);
  25502. setup$4(editor);
  25503. setup$3(editor);
  25504. };
  25505. const isWithinCaretContainer = node => isCaretContainer$2(node) || startsWithCaretContainer$1(node) || endsWithCaretContainer$1(node);
  25506. const isRangeInCaretContainer = rng => isWithinCaretContainer(rng.startContainer) || isWithinCaretContainer(rng.endContainer);
  25507. const normalizeVoidElementSelection = rng => {
  25508. const voidElements = editor.schema.getVoidElements();
  25509. const newRng = dom.createRng();
  25510. const startContainer = rng.startContainer;
  25511. const startOffset = rng.startOffset;
  25512. const endContainer = rng.endContainer;
  25513. const endOffset = rng.endOffset;
  25514. if (has$2(voidElements, startContainer.nodeName.toLowerCase())) {
  25515. if (startOffset === 0) {
  25516. newRng.setStartBefore(startContainer);
  25517. } else {
  25518. newRng.setStartAfter(startContainer);
  25519. }
  25520. } else {
  25521. newRng.setStart(startContainer, startOffset);
  25522. }
  25523. if (has$2(voidElements, endContainer.nodeName.toLowerCase())) {
  25524. if (endOffset === 0) {
  25525. newRng.setEndBefore(endContainer);
  25526. } else {
  25527. newRng.setEndAfter(endContainer);
  25528. }
  25529. } else {
  25530. newRng.setEnd(endContainer, endOffset);
  25531. }
  25532. return newRng;
  25533. };
  25534. const setupOffscreenSelection = (node, targetClone) => {
  25535. const body = SugarElement.fromDom(editor.getBody());
  25536. const doc = editor.getDoc();
  25537. const realSelectionContainer = descendant(body, '#' + realSelectionId).getOrThunk(() => {
  25538. const newContainer = SugarElement.fromHtml('<div data-mce-bogus="all" class="mce-offscreen-selection"></div>', doc);
  25539. set$2(newContainer, 'id', realSelectionId);
  25540. append$1(body, newContainer);
  25541. return newContainer;
  25542. });
  25543. const newRange = dom.createRng();
  25544. empty(realSelectionContainer);
  25545. append(realSelectionContainer, [
  25546. SugarElement.fromText(nbsp, doc),
  25547. SugarElement.fromDom(targetClone),
  25548. SugarElement.fromText(nbsp, doc)
  25549. ]);
  25550. newRange.setStart(realSelectionContainer.dom.firstChild, 1);
  25551. newRange.setEnd(realSelectionContainer.dom.lastChild, 0);
  25552. setAll(realSelectionContainer, { top: dom.getPos(node, editor.getBody()).y + 'px' });
  25553. focus$1(realSelectionContainer);
  25554. const sel = selection.getSel();
  25555. if (sel) {
  25556. sel.removeAllRanges();
  25557. sel.addRange(newRange);
  25558. }
  25559. return newRange;
  25560. };
  25561. const selectElement = elm => {
  25562. const targetClone = elm.cloneNode(true);
  25563. const e = editor.dispatch('ObjectSelected', {
  25564. target: elm,
  25565. targetClone
  25566. });
  25567. if (e.isDefaultPrevented()) {
  25568. return null;
  25569. }
  25570. const range = setupOffscreenSelection(elm, e.targetClone);
  25571. const nodeElm = SugarElement.fromDom(elm);
  25572. each$e(descendants(SugarElement.fromDom(editor.getBody()), `*[${ elementSelectionAttr }]`), elm => {
  25573. if (!eq(nodeElm, elm)) {
  25574. remove$b(elm, elementSelectionAttr);
  25575. }
  25576. });
  25577. if (!dom.getAttrib(elm, elementSelectionAttr)) {
  25578. elm.setAttribute(elementSelectionAttr, '1');
  25579. }
  25580. selectedElement = elm;
  25581. hideFakeCaret();
  25582. return range;
  25583. };
  25584. const setElementSelection = (range, forward) => {
  25585. if (!range) {
  25586. return null;
  25587. }
  25588. if (range.collapsed) {
  25589. if (!isRangeInCaretContainer(range)) {
  25590. const dir = forward ? 1 : -1;
  25591. const caretPosition = getNormalizedRangeEndPoint(dir, rootNode, range);
  25592. const beforeNode = caretPosition.getNode(!forward);
  25593. if (isNonNullable(beforeNode)) {
  25594. if (isFakeCaretTarget(beforeNode)) {
  25595. return showCaret(dir, beforeNode, forward ? !caretPosition.isAtEnd() : false, false);
  25596. }
  25597. if (isCaretContainerInline(beforeNode) && isContentEditableFalse$a(beforeNode.nextSibling)) {
  25598. const rng = dom.createRng();
  25599. rng.setStart(beforeNode, 0);
  25600. rng.setEnd(beforeNode, 0);
  25601. return rng;
  25602. }
  25603. }
  25604. const afterNode = caretPosition.getNode(forward);
  25605. if (isNonNullable(afterNode)) {
  25606. if (isFakeCaretTarget(afterNode)) {
  25607. return showCaret(dir, afterNode, forward ? false : !caretPosition.isAtEnd(), false);
  25608. }
  25609. if (isCaretContainerInline(afterNode) && isContentEditableFalse$a(afterNode.previousSibling)) {
  25610. const rng = dom.createRng();
  25611. rng.setStart(afterNode, 1);
  25612. rng.setEnd(afterNode, 1);
  25613. return rng;
  25614. }
  25615. }
  25616. }
  25617. return null;
  25618. }
  25619. let startContainer = range.startContainer;
  25620. let startOffset = range.startOffset;
  25621. const endOffset = range.endOffset;
  25622. if (isText$a(startContainer) && startOffset === 0 && isContentEditableFalse(startContainer.parentNode)) {
  25623. startContainer = startContainer.parentNode;
  25624. startOffset = dom.nodeIndex(startContainer);
  25625. startContainer = startContainer.parentNode;
  25626. }
  25627. if (!isElement$6(startContainer)) {
  25628. return null;
  25629. }
  25630. if (endOffset === startOffset + 1 && startContainer === range.endContainer) {
  25631. const node = startContainer.childNodes[startOffset];
  25632. if (isFakeSelectionTargetElement(node)) {
  25633. return selectElement(node);
  25634. }
  25635. }
  25636. return null;
  25637. };
  25638. const removeElementSelection = () => {
  25639. if (selectedElement) {
  25640. selectedElement.removeAttribute(elementSelectionAttr);
  25641. }
  25642. descendant(SugarElement.fromDom(editor.getBody()), '#' + realSelectionId).each(remove$6);
  25643. selectedElement = null;
  25644. };
  25645. const destroy = () => {
  25646. fakeCaret.destroy();
  25647. selectedElement = null;
  25648. };
  25649. const hideFakeCaret = () => {
  25650. fakeCaret.hide();
  25651. };
  25652. if (!isRtc(editor)) {
  25653. registerEvents();
  25654. }
  25655. return {
  25656. showCaret,
  25657. showBlockCaretContainer,
  25658. hideFakeCaret,
  25659. destroy
  25660. };
  25661. };
  25662. const getNormalizedTextOffset = (container, offset) => {
  25663. let normalizedOffset = offset;
  25664. for (let node = container.previousSibling; isText$a(node); node = node.previousSibling) {
  25665. normalizedOffset += node.data.length;
  25666. }
  25667. return normalizedOffset;
  25668. };
  25669. const generatePath = (dom, root, node, offset, normalized) => {
  25670. if (isText$a(node) && (offset < 0 || offset > node.data.length)) {
  25671. return [];
  25672. }
  25673. const p = normalized && isText$a(node) ? [getNormalizedTextOffset(node, offset)] : [offset];
  25674. let current = node;
  25675. while (current !== root && current.parentNode) {
  25676. p.push(dom.nodeIndex(current, normalized));
  25677. current = current.parentNode;
  25678. }
  25679. return current === root ? p.reverse() : [];
  25680. };
  25681. const generatePathRange = (dom, root, startNode, startOffset, endNode, endOffset, normalized = false) => {
  25682. const start = generatePath(dom, root, startNode, startOffset, normalized);
  25683. const end = generatePath(dom, root, endNode, endOffset, normalized);
  25684. return {
  25685. start,
  25686. end
  25687. };
  25688. };
  25689. const resolvePath = (root, path) => {
  25690. const nodePath = path.slice();
  25691. const offset = nodePath.pop();
  25692. if (!isNumber(offset)) {
  25693. return Optional.none();
  25694. } else {
  25695. const resolvedNode = foldl(nodePath, (optNode, index) => optNode.bind(node => Optional.from(node.childNodes[index])), Optional.some(root));
  25696. return resolvedNode.bind(node => {
  25697. if (isText$a(node) && (offset < 0 || offset > node.data.length)) {
  25698. return Optional.none();
  25699. } else {
  25700. return Optional.some({
  25701. node,
  25702. offset
  25703. });
  25704. }
  25705. });
  25706. }
  25707. };
  25708. const resolvePathRange = (root, range) => resolvePath(root, range.start).bind(({
  25709. node: startNode,
  25710. offset: startOffset
  25711. }) => resolvePath(root, range.end).map(({
  25712. node: endNode,
  25713. offset: endOffset
  25714. }) => {
  25715. const rng = document.createRange();
  25716. rng.setStart(startNode, startOffset);
  25717. rng.setEnd(endNode, endOffset);
  25718. return rng;
  25719. }));
  25720. const generatePathRangeFromRange = (dom, root, range, normalized = false) => generatePathRange(dom, root, range.startContainer, range.startOffset, range.endContainer, range.endOffset, normalized);
  25721. const cleanEmptyNodes = (dom, node, isRoot) => {
  25722. if (node && dom.isEmpty(node) && !isRoot(node)) {
  25723. const parent = node.parentNode;
  25724. dom.remove(node);
  25725. cleanEmptyNodes(dom, parent, isRoot);
  25726. }
  25727. };
  25728. const deleteRng = (dom, rng, isRoot, clean = true) => {
  25729. const startParent = rng.startContainer.parentNode;
  25730. const endParent = rng.endContainer.parentNode;
  25731. rng.deleteContents();
  25732. if (clean && !isRoot(rng.startContainer)) {
  25733. if (isText$a(rng.startContainer) && rng.startContainer.data.length === 0) {
  25734. dom.remove(rng.startContainer);
  25735. }
  25736. if (isText$a(rng.endContainer) && rng.endContainer.data.length === 0) {
  25737. dom.remove(rng.endContainer);
  25738. }
  25739. cleanEmptyNodes(dom, startParent, isRoot);
  25740. if (startParent !== endParent) {
  25741. cleanEmptyNodes(dom, endParent, isRoot);
  25742. }
  25743. }
  25744. };
  25745. const getParentBlock = (editor, rng) => Optional.from(editor.dom.getParent(rng.startContainer, editor.dom.isBlock));
  25746. const resolveFromDynamicPatterns = (patternSet, block, beforeText) => {
  25747. const dynamicPatterns = patternSet.dynamicPatternsLookup({
  25748. text: beforeText,
  25749. block
  25750. });
  25751. return {
  25752. ...patternSet,
  25753. blockPatterns: getBlockPatterns(dynamicPatterns).concat(patternSet.blockPatterns),
  25754. inlinePatterns: getInlinePatterns(dynamicPatterns).concat(patternSet.inlinePatterns)
  25755. };
  25756. };
  25757. const getBeforeText = (dom, block, node, offset) => {
  25758. const rng = dom.createRng();
  25759. rng.setStart(block, 0);
  25760. rng.setEnd(node, offset);
  25761. return rng.toString();
  25762. };
  25763. const stripPattern = (dom, block, pattern) => {
  25764. const firstTextNode = textAfter(block, 0, block);
  25765. firstTextNode.each(spot => {
  25766. const node = spot.container;
  25767. scanRight(node, pattern.start.length, block).each(end => {
  25768. const rng = dom.createRng();
  25769. rng.setStart(node, 0);
  25770. rng.setEnd(end.container, end.offset);
  25771. deleteRng(dom, rng, e => e === block);
  25772. });
  25773. });
  25774. };
  25775. const applyPattern$1 = (editor, match) => {
  25776. const dom = editor.dom;
  25777. const pattern = match.pattern;
  25778. const rng = resolvePathRange(dom.getRoot(), match.range).getOrDie('Unable to resolve path range');
  25779. const isBlockFormatName = (name, formatter) => {
  25780. const formatSet = formatter.get(name);
  25781. return isArray$1(formatSet) && head(formatSet).exists(format => has$2(format, 'block'));
  25782. };
  25783. getParentBlock(editor, rng).each(block => {
  25784. if (pattern.type === 'block-format') {
  25785. if (isBlockFormatName(pattern.format, editor.formatter)) {
  25786. editor.undoManager.transact(() => {
  25787. stripPattern(editor.dom, block, pattern);
  25788. editor.formatter.apply(pattern.format);
  25789. });
  25790. }
  25791. } else if (pattern.type === 'block-command') {
  25792. editor.undoManager.transact(() => {
  25793. stripPattern(editor.dom, block, pattern);
  25794. editor.execCommand(pattern.cmd, false, pattern.value);
  25795. });
  25796. }
  25797. });
  25798. return true;
  25799. };
  25800. const sortPatterns$1 = patterns => sort(patterns, (a, b) => b.start.length - a.start.length);
  25801. const findPattern$1 = (patterns, text) => {
  25802. const sortedPatterns = sortPatterns$1(patterns);
  25803. const nuText = text.replace(nbsp, ' ');
  25804. return find$2(sortedPatterns, pattern => text.indexOf(pattern.start) === 0 || nuText.indexOf(pattern.start) === 0);
  25805. };
  25806. const findPatterns$1 = (editor, block, patternSet, normalizedMatches) => {
  25807. var _a;
  25808. const dom = editor.dom;
  25809. const forcedRootBlock = getForcedRootBlock(editor);
  25810. if (!dom.is(block, forcedRootBlock)) {
  25811. return [];
  25812. }
  25813. const blockText = (_a = block.textContent) !== null && _a !== void 0 ? _a : '';
  25814. return findPattern$1(patternSet.blockPatterns, blockText).map(pattern => {
  25815. if (Tools.trim(blockText).length === pattern.start.length) {
  25816. return [];
  25817. }
  25818. return [{
  25819. pattern,
  25820. range: generatePathRange(dom, dom.getRoot(), block, 0, block, 0, normalizedMatches)
  25821. }];
  25822. }).getOr([]);
  25823. };
  25824. const applyMatches$1 = (editor, matches) => {
  25825. if (matches.length === 0) {
  25826. return;
  25827. }
  25828. const bookmark = editor.selection.getBookmark();
  25829. each$e(matches, match => applyPattern$1(editor, match));
  25830. editor.selection.moveToBookmark(bookmark);
  25831. };
  25832. const newMarker = (dom, id) => dom.create('span', {
  25833. 'data-mce-type': 'bookmark',
  25834. id
  25835. });
  25836. const rangeFromMarker = (dom, marker) => {
  25837. const rng = dom.createRng();
  25838. rng.setStartAfter(marker.start);
  25839. rng.setEndBefore(marker.end);
  25840. return rng;
  25841. };
  25842. const createMarker = (dom, markerPrefix, pathRange) => {
  25843. const rng = resolvePathRange(dom.getRoot(), pathRange).getOrDie('Unable to resolve path range');
  25844. const startNode = rng.startContainer;
  25845. const endNode = rng.endContainer;
  25846. const textEnd = rng.endOffset === 0 ? endNode : endNode.splitText(rng.endOffset);
  25847. const textStart = rng.startOffset === 0 ? startNode : startNode.splitText(rng.startOffset);
  25848. const startParentNode = textStart.parentNode;
  25849. const endParentNode = textEnd.parentNode;
  25850. return {
  25851. prefix: markerPrefix,
  25852. end: endParentNode.insertBefore(newMarker(dom, markerPrefix + '-end'), textEnd),
  25853. start: startParentNode.insertBefore(newMarker(dom, markerPrefix + '-start'), textStart)
  25854. };
  25855. };
  25856. const removeMarker = (dom, marker, isRoot) => {
  25857. cleanEmptyNodes(dom, dom.get(marker.prefix + '-end'), isRoot);
  25858. cleanEmptyNodes(dom, dom.get(marker.prefix + '-start'), isRoot);
  25859. };
  25860. const isReplacementPattern = pattern => pattern.start.length === 0;
  25861. const matchesPattern = patternContent => (element, offset) => {
  25862. const text = element.data;
  25863. const searchText = text.substring(0, offset);
  25864. const startEndIndex = searchText.lastIndexOf(patternContent.charAt(patternContent.length - 1));
  25865. const startIndex = searchText.lastIndexOf(patternContent);
  25866. if (startIndex !== -1) {
  25867. return startIndex + patternContent.length;
  25868. } else if (startEndIndex !== -1) {
  25869. return startEndIndex + 1;
  25870. } else {
  25871. return -1;
  25872. }
  25873. };
  25874. const findPatternStartFromSpot = (dom, pattern, block, spot) => {
  25875. const startPattern = pattern.start;
  25876. const startSpot = repeatLeft(dom, spot.container, spot.offset, matchesPattern(startPattern), block);
  25877. return startSpot.bind(spot => {
  25878. var _a, _b;
  25879. const startPatternIndex = (_b = (_a = block.textContent) === null || _a === void 0 ? void 0 : _a.indexOf(startPattern)) !== null && _b !== void 0 ? _b : -1;
  25880. const isCompleteMatch = startPatternIndex !== -1 && spot.offset >= startPatternIndex + startPattern.length;
  25881. if (isCompleteMatch) {
  25882. const rng = dom.createRng();
  25883. rng.setStart(spot.container, spot.offset - startPattern.length);
  25884. rng.setEnd(spot.container, spot.offset);
  25885. return Optional.some(rng);
  25886. } else {
  25887. const offset = spot.offset - startPattern.length;
  25888. return scanLeft(spot.container, offset, block).map(nextSpot => {
  25889. const rng = dom.createRng();
  25890. rng.setStart(nextSpot.container, nextSpot.offset);
  25891. rng.setEnd(spot.container, spot.offset);
  25892. return rng;
  25893. }).filter(rng => rng.toString() === startPattern).orThunk(() => findPatternStartFromSpot(dom, pattern, block, point(spot.container, 0)));
  25894. }
  25895. });
  25896. };
  25897. const findPatternStart = (dom, pattern, node, offset, block, requireGap = false) => {
  25898. if (pattern.start.length === 0 && !requireGap) {
  25899. const rng = dom.createRng();
  25900. rng.setStart(node, offset);
  25901. rng.setEnd(node, offset);
  25902. return Optional.some(rng);
  25903. }
  25904. return textBefore(node, offset, block).bind(spot => {
  25905. const start = findPatternStartFromSpot(dom, pattern, block, spot);
  25906. return start.bind(startRange => {
  25907. var _a;
  25908. if (requireGap) {
  25909. if (startRange.endContainer === spot.container && startRange.endOffset === spot.offset) {
  25910. return Optional.none();
  25911. } else if (spot.offset === 0 && ((_a = startRange.endContainer.textContent) === null || _a === void 0 ? void 0 : _a.length) === startRange.endOffset) {
  25912. return Optional.none();
  25913. }
  25914. }
  25915. return Optional.some(startRange);
  25916. });
  25917. });
  25918. };
  25919. const findPattern = (editor, block, details, normalizedMatches) => {
  25920. const dom = editor.dom;
  25921. const root = dom.getRoot();
  25922. const pattern = details.pattern;
  25923. const endNode = details.position.container;
  25924. const endOffset = details.position.offset;
  25925. return scanLeft(endNode, endOffset - details.pattern.end.length, block).bind(spot => {
  25926. const endPathRng = generatePathRange(dom, root, spot.container, spot.offset, endNode, endOffset, normalizedMatches);
  25927. if (isReplacementPattern(pattern)) {
  25928. return Optional.some({
  25929. matches: [{
  25930. pattern,
  25931. startRng: endPathRng,
  25932. endRng: endPathRng
  25933. }],
  25934. position: spot
  25935. });
  25936. } else {
  25937. const resultsOpt = findPatternsRec(editor, details.remainingPatterns, spot.container, spot.offset, block, normalizedMatches);
  25938. const results = resultsOpt.getOr({
  25939. matches: [],
  25940. position: spot
  25941. });
  25942. const pos = results.position;
  25943. const start = findPatternStart(dom, pattern, pos.container, pos.offset, block, resultsOpt.isNone());
  25944. return start.map(startRng => {
  25945. const startPathRng = generatePathRangeFromRange(dom, root, startRng, normalizedMatches);
  25946. return {
  25947. matches: results.matches.concat([{
  25948. pattern,
  25949. startRng: startPathRng,
  25950. endRng: endPathRng
  25951. }]),
  25952. position: point(startRng.startContainer, startRng.startOffset)
  25953. };
  25954. });
  25955. }
  25956. });
  25957. };
  25958. const findPatternsRec = (editor, patterns, node, offset, block, normalizedMatches) => {
  25959. const dom = editor.dom;
  25960. return textBefore(node, offset, dom.getRoot()).bind(endSpot => {
  25961. const text = getBeforeText(dom, block, node, offset);
  25962. for (let i = 0; i < patterns.length; i++) {
  25963. const pattern = patterns[i];
  25964. if (!endsWith(text, pattern.end)) {
  25965. continue;
  25966. }
  25967. const patternsWithoutCurrent = patterns.slice();
  25968. patternsWithoutCurrent.splice(i, 1);
  25969. const result = findPattern(editor, block, {
  25970. pattern,
  25971. remainingPatterns: patternsWithoutCurrent,
  25972. position: endSpot
  25973. }, normalizedMatches);
  25974. if (result.isNone() && offset > 0) {
  25975. return findPatternsRec(editor, patterns, node, offset - 1, block, normalizedMatches);
  25976. }
  25977. if (result.isSome()) {
  25978. return result;
  25979. }
  25980. }
  25981. return Optional.none();
  25982. });
  25983. };
  25984. const applyPattern = (editor, pattern, patternRange) => {
  25985. editor.selection.setRng(patternRange);
  25986. if (pattern.type === 'inline-format') {
  25987. each$e(pattern.format, format => {
  25988. editor.formatter.apply(format);
  25989. });
  25990. } else {
  25991. editor.execCommand(pattern.cmd, false, pattern.value);
  25992. }
  25993. };
  25994. const applyReplacementPattern = (editor, pattern, marker, isRoot) => {
  25995. const markerRange = rangeFromMarker(editor.dom, marker);
  25996. deleteRng(editor.dom, markerRange, isRoot);
  25997. applyPattern(editor, pattern, markerRange);
  25998. };
  25999. const applyPatternWithContent = (editor, pattern, startMarker, endMarker, isRoot) => {
  26000. const dom = editor.dom;
  26001. const markerEndRange = rangeFromMarker(dom, endMarker);
  26002. const markerStartRange = rangeFromMarker(dom, startMarker);
  26003. deleteRng(dom, markerStartRange, isRoot);
  26004. deleteRng(dom, markerEndRange, isRoot);
  26005. const patternMarker = {
  26006. prefix: startMarker.prefix,
  26007. start: startMarker.end,
  26008. end: endMarker.start
  26009. };
  26010. const patternRange = rangeFromMarker(dom, patternMarker);
  26011. applyPattern(editor, pattern, patternRange);
  26012. };
  26013. const addMarkers = (dom, matches) => {
  26014. const markerPrefix = generate$1('mce_textpattern');
  26015. const matchesWithEnds = foldr(matches, (acc, match) => {
  26016. const endMarker = createMarker(dom, markerPrefix + `_end${ acc.length }`, match.endRng);
  26017. return acc.concat([{
  26018. ...match,
  26019. endMarker
  26020. }]);
  26021. }, []);
  26022. return foldr(matchesWithEnds, (acc, match) => {
  26023. const idx = matchesWithEnds.length - acc.length - 1;
  26024. const startMarker = isReplacementPattern(match.pattern) ? match.endMarker : createMarker(dom, markerPrefix + `_start${ idx }`, match.startRng);
  26025. return acc.concat([{
  26026. ...match,
  26027. startMarker
  26028. }]);
  26029. }, []);
  26030. };
  26031. const sortPatterns = patterns => sort(patterns, (a, b) => b.end.length - a.end.length);
  26032. const getBestMatches = (matches, matchesWithSortedPatterns) => {
  26033. const hasSameMatches = forall(matches, match => exists(matchesWithSortedPatterns, sortedMatch => match.pattern.start === sortedMatch.pattern.start && match.pattern.end === sortedMatch.pattern.end));
  26034. if (matches.length === matchesWithSortedPatterns.length) {
  26035. if (hasSameMatches) {
  26036. return matches;
  26037. } else {
  26038. return matchesWithSortedPatterns;
  26039. }
  26040. }
  26041. return matches.length > matchesWithSortedPatterns.length ? matches : matchesWithSortedPatterns;
  26042. };
  26043. const findPatterns = (editor, block, node, offset, patternSet, normalizedMatches) => {
  26044. const matches = findPatternsRec(editor, patternSet.inlinePatterns, node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
  26045. const matchesWithSortedPatterns = findPatternsRec(editor, sortPatterns(patternSet.inlinePatterns), node, offset, block, normalizedMatches).fold(() => [], result => result.matches);
  26046. return getBestMatches(matches, matchesWithSortedPatterns);
  26047. };
  26048. const applyMatches = (editor, matches) => {
  26049. if (matches.length === 0) {
  26050. return;
  26051. }
  26052. const dom = editor.dom;
  26053. const bookmark = editor.selection.getBookmark();
  26054. const matchesWithMarkers = addMarkers(dom, matches);
  26055. each$e(matchesWithMarkers, match => {
  26056. const block = dom.getParent(match.startMarker.start, dom.isBlock);
  26057. const isRoot = node => node === block;
  26058. if (isReplacementPattern(match.pattern)) {
  26059. applyReplacementPattern(editor, match.pattern, match.endMarker, isRoot);
  26060. } else {
  26061. applyPatternWithContent(editor, match.pattern, match.startMarker, match.endMarker, isRoot);
  26062. }
  26063. removeMarker(dom, match.endMarker, isRoot);
  26064. removeMarker(dom, match.startMarker, isRoot);
  26065. });
  26066. editor.selection.moveToBookmark(bookmark);
  26067. };
  26068. const handleEnter = (editor, patternSet) => {
  26069. const rng = editor.selection.getRng();
  26070. return getParentBlock(editor, rng).map(block => {
  26071. var _a;
  26072. const offset = Math.max(0, rng.startOffset);
  26073. const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, (_a = block.textContent) !== null && _a !== void 0 ? _a : '');
  26074. const inlineMatches = findPatterns(editor, block, rng.startContainer, offset, dynamicPatternSet, true);
  26075. const blockMatches = findPatterns$1(editor, block, dynamicPatternSet, true);
  26076. if (blockMatches.length > 0 || inlineMatches.length > 0) {
  26077. editor.undoManager.add();
  26078. editor.undoManager.extra(() => {
  26079. editor.execCommand('mceInsertNewLine');
  26080. }, () => {
  26081. editor.insertContent(zeroWidth);
  26082. applyMatches(editor, inlineMatches);
  26083. applyMatches$1(editor, blockMatches);
  26084. const range = editor.selection.getRng();
  26085. const spot = textBefore(range.startContainer, range.startOffset, editor.dom.getRoot());
  26086. editor.execCommand('mceInsertNewLine');
  26087. spot.each(s => {
  26088. const node = s.container;
  26089. if (node.data.charAt(s.offset - 1) === zeroWidth) {
  26090. node.deleteData(s.offset - 1, 1);
  26091. cleanEmptyNodes(editor.dom, node.parentNode, e => e === editor.dom.getRoot());
  26092. }
  26093. });
  26094. });
  26095. return true;
  26096. }
  26097. return false;
  26098. }).getOr(false);
  26099. };
  26100. const handleInlineKey = (editor, patternSet) => {
  26101. const rng = editor.selection.getRng();
  26102. getParentBlock(editor, rng).map(block => {
  26103. const offset = Math.max(0, rng.startOffset - 1);
  26104. const beforeText = getBeforeText(editor.dom, block, rng.startContainer, offset);
  26105. const dynamicPatternSet = resolveFromDynamicPatterns(patternSet, block, beforeText);
  26106. const inlineMatches = findPatterns(editor, block, rng.startContainer, offset, dynamicPatternSet, false);
  26107. if (inlineMatches.length > 0) {
  26108. editor.undoManager.transact(() => {
  26109. applyMatches(editor, inlineMatches);
  26110. });
  26111. }
  26112. });
  26113. };
  26114. const checkKeyEvent = (codes, event, predicate) => {
  26115. for (let i = 0; i < codes.length; i++) {
  26116. if (predicate(codes[i], event)) {
  26117. return true;
  26118. }
  26119. }
  26120. return false;
  26121. };
  26122. const checkKeyCode = (codes, event) => checkKeyEvent(codes, event, (code, event) => {
  26123. return code === event.keyCode && !VK.modifierPressed(event);
  26124. });
  26125. const checkCharCode = (chars, event) => checkKeyEvent(chars, event, (chr, event) => {
  26126. return chr.charCodeAt(0) === event.charCode;
  26127. });
  26128. const setup$2 = editor => {
  26129. const charCodes = [
  26130. ',',
  26131. '.',
  26132. ';',
  26133. ':',
  26134. '!',
  26135. '?'
  26136. ];
  26137. const keyCodes = [32];
  26138. const getPatternSet = () => createPatternSet(getTextPatterns(editor), getTextPatternsLookup(editor));
  26139. const hasDynamicPatterns = () => hasTextPatternsLookup(editor);
  26140. editor.on('keydown', e => {
  26141. if (e.keyCode === 13 && !VK.modifierPressed(e) && editor.selection.isCollapsed()) {
  26142. const patternSet = getPatternSet();
  26143. const hasPatterns = patternSet.inlinePatterns.length > 0 || patternSet.blockPatterns.length > 0 || hasDynamicPatterns();
  26144. if (hasPatterns && handleEnter(editor, patternSet)) {
  26145. e.preventDefault();
  26146. }
  26147. }
  26148. }, true);
  26149. const handleInlineTrigger = () => {
  26150. if (editor.selection.isCollapsed()) {
  26151. const patternSet = getPatternSet();
  26152. const hasPatterns = patternSet.inlinePatterns.length > 0 || hasDynamicPatterns();
  26153. if (hasPatterns) {
  26154. handleInlineKey(editor, patternSet);
  26155. }
  26156. }
  26157. };
  26158. editor.on('keyup', e => {
  26159. if (checkKeyCode(keyCodes, e)) {
  26160. handleInlineTrigger();
  26161. }
  26162. });
  26163. editor.on('keypress', e => {
  26164. if (checkCharCode(charCodes, e)) {
  26165. Delay.setEditorTimeout(editor, handleInlineTrigger);
  26166. }
  26167. });
  26168. };
  26169. const setup$1 = editor => {
  26170. setup$2(editor);
  26171. };
  26172. const Quirks = editor => {
  26173. const each = Tools.each;
  26174. const BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, parser = editor.parser;
  26175. const browser = Env.browser;
  26176. const isGecko = browser.isFirefox();
  26177. const isWebKit = browser.isChromium() || browser.isSafari();
  26178. const isiOS = Env.deviceType.isiPhone() || Env.deviceType.isiPad();
  26179. const isMac = Env.os.isMacOS() || Env.os.isiOS();
  26180. const setEditorCommandState = (cmd, state) => {
  26181. try {
  26182. editor.getDoc().execCommand(cmd, false, String(state));
  26183. } catch (ex) {
  26184. }
  26185. };
  26186. const isDefaultPrevented = e => {
  26187. return e.isDefaultPrevented();
  26188. };
  26189. const emptyEditorWhenDeleting = () => {
  26190. const serializeRng = rng => {
  26191. const body = dom.create('body');
  26192. const contents = rng.cloneContents();
  26193. body.appendChild(contents);
  26194. return selection.serializer.serialize(body, { format: 'html' });
  26195. };
  26196. const allContentsSelected = rng => {
  26197. const selection = serializeRng(rng);
  26198. const allRng = dom.createRng();
  26199. allRng.selectNode(editor.getBody());
  26200. const allSelection = serializeRng(allRng);
  26201. return selection === allSelection;
  26202. };
  26203. editor.on('keydown', e => {
  26204. const keyCode = e.keyCode;
  26205. if (!isDefaultPrevented(e) && (keyCode === DELETE || keyCode === BACKSPACE)) {
  26206. const isCollapsed = editor.selection.isCollapsed();
  26207. const body = editor.getBody();
  26208. if (isCollapsed && !dom.isEmpty(body)) {
  26209. return;
  26210. }
  26211. if (!isCollapsed && !allContentsSelected(editor.selection.getRng())) {
  26212. return;
  26213. }
  26214. e.preventDefault();
  26215. editor.setContent('');
  26216. if (body.firstChild && dom.isBlock(body.firstChild)) {
  26217. editor.selection.setCursorLocation(body.firstChild, 0);
  26218. } else {
  26219. editor.selection.setCursorLocation(body, 0);
  26220. }
  26221. editor.nodeChanged();
  26222. }
  26223. });
  26224. };
  26225. const selectAll = () => {
  26226. editor.shortcuts.add('meta+a', null, 'SelectAll');
  26227. };
  26228. const documentElementEditingFocus = () => {
  26229. if (!editor.inline) {
  26230. dom.bind(editor.getDoc(), 'mousedown mouseup', e => {
  26231. let rng;
  26232. if (e.target === editor.getDoc().documentElement) {
  26233. rng = selection.getRng();
  26234. editor.getBody().focus();
  26235. if (e.type === 'mousedown') {
  26236. if (isCaretContainer$2(rng.startContainer)) {
  26237. return;
  26238. }
  26239. selection.placeCaretAt(e.clientX, e.clientY);
  26240. } else {
  26241. selection.setRng(rng);
  26242. }
  26243. }
  26244. });
  26245. }
  26246. };
  26247. const removeHrOnBackspace = () => {
  26248. editor.on('keydown', e => {
  26249. if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
  26250. if (!editor.getBody().getElementsByTagName('hr').length) {
  26251. return;
  26252. }
  26253. if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
  26254. const node = selection.getNode();
  26255. const previousSibling = node.previousSibling;
  26256. if (node.nodeName === 'HR') {
  26257. dom.remove(node);
  26258. e.preventDefault();
  26259. return;
  26260. }
  26261. if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'hr') {
  26262. dom.remove(previousSibling);
  26263. e.preventDefault();
  26264. }
  26265. }
  26266. }
  26267. });
  26268. };
  26269. const focusBody = () => {
  26270. if (!Range.prototype.getClientRects) {
  26271. editor.on('mousedown', e => {
  26272. if (!isDefaultPrevented(e) && e.target.nodeName === 'HTML') {
  26273. const body = editor.getBody();
  26274. body.blur();
  26275. Delay.setEditorTimeout(editor, () => {
  26276. body.focus();
  26277. });
  26278. }
  26279. });
  26280. }
  26281. };
  26282. const selectControlElements = () => {
  26283. const visualAidsAnchorClass = getVisualAidsAnchorClass(editor);
  26284. editor.on('click', e => {
  26285. const target = e.target;
  26286. if (/^(IMG|HR)$/.test(target.nodeName) && dom.getContentEditableParent(target) !== 'false') {
  26287. e.preventDefault();
  26288. editor.selection.select(target);
  26289. editor.nodeChanged();
  26290. }
  26291. if (target.nodeName === 'A' && dom.hasClass(target, visualAidsAnchorClass) && target.childNodes.length === 0) {
  26292. e.preventDefault();
  26293. selection.select(target);
  26294. }
  26295. });
  26296. };
  26297. const removeStylesWhenDeletingAcrossBlockElements = () => {
  26298. const getAttributeApplyFunction = () => {
  26299. const template = dom.getAttribs(selection.getStart().cloneNode(false));
  26300. return () => {
  26301. const target = selection.getStart();
  26302. if (target !== editor.getBody()) {
  26303. dom.setAttrib(target, 'style', null);
  26304. each(template, attr => {
  26305. target.setAttributeNode(attr.cloneNode(true));
  26306. });
  26307. }
  26308. };
  26309. };
  26310. const isSelectionAcrossElements = () => {
  26311. return !selection.isCollapsed() && dom.getParent(selection.getStart(), dom.isBlock) !== dom.getParent(selection.getEnd(), dom.isBlock);
  26312. };
  26313. editor.on('keypress', e => {
  26314. let applyAttributes;
  26315. if (!isDefaultPrevented(e) && (e.keyCode === 8 || e.keyCode === 46) && isSelectionAcrossElements()) {
  26316. applyAttributes = getAttributeApplyFunction();
  26317. editor.getDoc().execCommand('delete', false);
  26318. applyAttributes();
  26319. e.preventDefault();
  26320. return false;
  26321. } else {
  26322. return true;
  26323. }
  26324. });
  26325. dom.bind(editor.getDoc(), 'cut', e => {
  26326. if (!isDefaultPrevented(e) && isSelectionAcrossElements()) {
  26327. const applyAttributes = getAttributeApplyFunction();
  26328. Delay.setEditorTimeout(editor, () => {
  26329. applyAttributes();
  26330. });
  26331. }
  26332. });
  26333. };
  26334. const disableBackspaceIntoATable = () => {
  26335. editor.on('keydown', e => {
  26336. if (!isDefaultPrevented(e) && e.keyCode === BACKSPACE) {
  26337. if (selection.isCollapsed() && selection.getRng().startOffset === 0) {
  26338. const previousSibling = selection.getNode().previousSibling;
  26339. if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === 'table') {
  26340. e.preventDefault();
  26341. return false;
  26342. }
  26343. }
  26344. }
  26345. return true;
  26346. });
  26347. };
  26348. const removeBlockQuoteOnBackSpace = () => {
  26349. editor.on('keydown', e => {
  26350. if (isDefaultPrevented(e) || e.keyCode !== VK.BACKSPACE) {
  26351. return;
  26352. }
  26353. let rng = selection.getRng();
  26354. const container = rng.startContainer;
  26355. const offset = rng.startOffset;
  26356. const root = dom.getRoot();
  26357. let parent = container;
  26358. if (!rng.collapsed || offset !== 0) {
  26359. return;
  26360. }
  26361. while (parent.parentNode && parent.parentNode.firstChild === parent && parent.parentNode !== root) {
  26362. parent = parent.parentNode;
  26363. }
  26364. if (parent.nodeName === 'BLOCKQUOTE') {
  26365. editor.formatter.toggle('blockquote', undefined, parent);
  26366. rng = dom.createRng();
  26367. rng.setStart(container, 0);
  26368. rng.setEnd(container, 0);
  26369. selection.setRng(rng);
  26370. }
  26371. });
  26372. };
  26373. const setGeckoEditingOptions = () => {
  26374. const setOpts = () => {
  26375. setEditorCommandState('StyleWithCSS', false);
  26376. setEditorCommandState('enableInlineTableEditing', false);
  26377. if (!getObjectResizing(editor)) {
  26378. setEditorCommandState('enableObjectResizing', false);
  26379. }
  26380. };
  26381. if (!isReadOnly$1(editor)) {
  26382. editor.on('BeforeExecCommand mousedown', setOpts);
  26383. }
  26384. };
  26385. const addBrAfterLastLinks = () => {
  26386. const fixLinks = () => {
  26387. each(dom.select('a:not([data-mce-block])'), node => {
  26388. var _a;
  26389. let parentNode = node.parentNode;
  26390. const root = dom.getRoot();
  26391. if ((parentNode === null || parentNode === void 0 ? void 0 : parentNode.lastChild) === node) {
  26392. while (parentNode && !dom.isBlock(parentNode)) {
  26393. if (((_a = parentNode.parentNode) === null || _a === void 0 ? void 0 : _a.lastChild) !== parentNode || parentNode === root) {
  26394. return;
  26395. }
  26396. parentNode = parentNode.parentNode;
  26397. }
  26398. dom.add(parentNode, 'br', { 'data-mce-bogus': 1 });
  26399. }
  26400. });
  26401. };
  26402. editor.on('SetContent ExecCommand', e => {
  26403. if (e.type === 'setcontent' || e.command === 'mceInsertLink') {
  26404. fixLinks();
  26405. }
  26406. });
  26407. };
  26408. const setDefaultBlockType = () => {
  26409. editor.on('init', () => {
  26410. setEditorCommandState('DefaultParagraphSeparator', getForcedRootBlock(editor));
  26411. });
  26412. };
  26413. const isAllContentSelected = editor => {
  26414. const body = editor.getBody();
  26415. const rng = editor.selection.getRng();
  26416. return rng.startContainer === rng.endContainer && rng.startContainer === body && rng.startOffset === 0 && rng.endOffset === body.childNodes.length;
  26417. };
  26418. const normalizeSelection = () => {
  26419. editor.on('keyup focusin mouseup', e => {
  26420. if (!VK.modifierPressed(e) && !isAllContentSelected(editor)) {
  26421. selection.normalize();
  26422. }
  26423. }, true);
  26424. };
  26425. const showBrokenImageIcon = () => {
  26426. editor.contentStyles.push('img:-moz-broken {' + '-moz-force-broken-image-icon:1;' + 'min-width:24px;' + 'min-height:24px' + '}');
  26427. };
  26428. const restoreFocusOnKeyDown = () => {
  26429. if (!editor.inline) {
  26430. editor.on('keydown', () => {
  26431. if (document.activeElement === document.body) {
  26432. editor.getWin().focus();
  26433. }
  26434. });
  26435. }
  26436. };
  26437. const bodyHeight = () => {
  26438. if (!editor.inline) {
  26439. editor.contentStyles.push('body {min-height: 150px}');
  26440. editor.on('click', e => {
  26441. let rng;
  26442. if (e.target.nodeName === 'HTML') {
  26443. rng = editor.selection.getRng();
  26444. editor.getBody().focus();
  26445. editor.selection.setRng(rng);
  26446. editor.selection.normalize();
  26447. editor.nodeChanged();
  26448. }
  26449. });
  26450. }
  26451. };
  26452. const blockCmdArrowNavigation = () => {
  26453. if (isMac) {
  26454. editor.on('keydown', e => {
  26455. if (VK.metaKeyPressed(e) && !e.shiftKey && (e.keyCode === 37 || e.keyCode === 39)) {
  26456. e.preventDefault();
  26457. const selection = editor.selection.getSel();
  26458. selection.modify('move', e.keyCode === 37 ? 'backward' : 'forward', 'lineboundary');
  26459. }
  26460. });
  26461. }
  26462. };
  26463. const tapLinksAndImages = () => {
  26464. editor.on('click', e => {
  26465. let elm = e.target;
  26466. do {
  26467. if (elm.tagName === 'A') {
  26468. e.preventDefault();
  26469. return;
  26470. }
  26471. } while (elm = elm.parentNode);
  26472. });
  26473. editor.contentStyles.push('.mce-content-body {-webkit-touch-callout: none}');
  26474. };
  26475. const blockFormSubmitInsideEditor = () => {
  26476. editor.on('init', () => {
  26477. editor.dom.bind(editor.getBody(), 'submit', e => {
  26478. e.preventDefault();
  26479. });
  26480. });
  26481. };
  26482. const removeAppleInterchangeBrs = () => {
  26483. parser.addNodeFilter('br', nodes => {
  26484. let i = nodes.length;
  26485. while (i--) {
  26486. if (nodes[i].attr('class') === 'Apple-interchange-newline') {
  26487. nodes[i].remove();
  26488. }
  26489. }
  26490. });
  26491. };
  26492. const refreshContentEditable = noop;
  26493. const isHidden = () => {
  26494. if (!isGecko || editor.removed) {
  26495. return false;
  26496. }
  26497. const sel = editor.selection.getSel();
  26498. return !sel || !sel.rangeCount || sel.rangeCount === 0;
  26499. };
  26500. const setupRtc = () => {
  26501. if (isWebKit) {
  26502. documentElementEditingFocus();
  26503. selectControlElements();
  26504. blockFormSubmitInsideEditor();
  26505. selectAll();
  26506. if (isiOS) {
  26507. restoreFocusOnKeyDown();
  26508. bodyHeight();
  26509. tapLinksAndImages();
  26510. }
  26511. }
  26512. if (isGecko) {
  26513. focusBody();
  26514. setGeckoEditingOptions();
  26515. showBrokenImageIcon();
  26516. blockCmdArrowNavigation();
  26517. }
  26518. };
  26519. const setup = () => {
  26520. removeBlockQuoteOnBackSpace();
  26521. emptyEditorWhenDeleting();
  26522. if (!Env.windowsPhone) {
  26523. normalizeSelection();
  26524. }
  26525. if (isWebKit) {
  26526. documentElementEditingFocus();
  26527. selectControlElements();
  26528. setDefaultBlockType();
  26529. blockFormSubmitInsideEditor();
  26530. disableBackspaceIntoATable();
  26531. removeAppleInterchangeBrs();
  26532. if (isiOS) {
  26533. restoreFocusOnKeyDown();
  26534. bodyHeight();
  26535. tapLinksAndImages();
  26536. } else {
  26537. selectAll();
  26538. }
  26539. }
  26540. if (isGecko) {
  26541. removeHrOnBackspace();
  26542. focusBody();
  26543. removeStylesWhenDeletingAcrossBlockElements();
  26544. setGeckoEditingOptions();
  26545. addBrAfterLastLinks();
  26546. showBrokenImageIcon();
  26547. blockCmdArrowNavigation();
  26548. disableBackspaceIntoATable();
  26549. }
  26550. };
  26551. if (isRtc(editor)) {
  26552. setupRtc();
  26553. } else {
  26554. setup();
  26555. }
  26556. return {
  26557. refreshContentEditable,
  26558. isHidden
  26559. };
  26560. };
  26561. const DOM$6 = DOMUtils.DOM;
  26562. const appendStyle = (editor, text) => {
  26563. const body = SugarElement.fromDom(editor.getBody());
  26564. const container = getStyleContainer(getRootNode(body));
  26565. const style = SugarElement.fromTag('style');
  26566. set$2(style, 'type', 'text/css');
  26567. append$1(style, SugarElement.fromText(text));
  26568. append$1(container, style);
  26569. editor.on('remove', () => {
  26570. remove$6(style);
  26571. });
  26572. };
  26573. const getRootName = editor => editor.inline ? editor.getElement().nodeName.toLowerCase() : undefined;
  26574. const removeUndefined = obj => filter$4(obj, v => isUndefined(v) === false);
  26575. const mkParserSettings = editor => {
  26576. const getOption = editor.options.get;
  26577. const blobCache = editor.editorUpload.blobCache;
  26578. return removeUndefined({
  26579. allow_conditional_comments: getOption('allow_conditional_comments'),
  26580. allow_html_data_urls: getOption('allow_html_data_urls'),
  26581. allow_svg_data_urls: getOption('allow_svg_data_urls'),
  26582. allow_html_in_named_anchor: getOption('allow_html_in_named_anchor'),
  26583. allow_script_urls: getOption('allow_script_urls'),
  26584. allow_unsafe_link_target: getOption('allow_unsafe_link_target'),
  26585. convert_fonts_to_spans: getOption('convert_fonts_to_spans'),
  26586. fix_list_elements: getOption('fix_list_elements'),
  26587. font_size_legacy_values: getOption('font_size_legacy_values'),
  26588. forced_root_block: getOption('forced_root_block'),
  26589. forced_root_block_attrs: getOption('forced_root_block_attrs'),
  26590. preserve_cdata: getOption('preserve_cdata'),
  26591. remove_trailing_brs: getOption('remove_trailing_brs'),
  26592. inline_styles: getOption('inline_styles'),
  26593. root_name: getRootName(editor),
  26594. validate: true,
  26595. blob_cache: blobCache,
  26596. document: editor.getDoc()
  26597. });
  26598. };
  26599. const mkSchemaSettings = editor => {
  26600. const getOption = editor.options.get;
  26601. return removeUndefined({
  26602. custom_elements: getOption('custom_elements'),
  26603. extended_valid_elements: getOption('extended_valid_elements'),
  26604. invalid_elements: getOption('invalid_elements'),
  26605. invalid_styles: getOption('invalid_styles'),
  26606. schema: getOption('schema'),
  26607. valid_children: getOption('valid_children'),
  26608. valid_classes: getOption('valid_classes'),
  26609. valid_elements: getOption('valid_elements'),
  26610. valid_styles: getOption('valid_styles'),
  26611. verify_html: getOption('verify_html'),
  26612. padd_empty_block_inline_children: getOption('format_empty_lines')
  26613. });
  26614. };
  26615. const mkSerializerSettings = editor => {
  26616. const getOption = editor.options.get;
  26617. return {
  26618. ...mkParserSettings(editor),
  26619. ...mkSchemaSettings(editor),
  26620. ...removeUndefined({
  26621. url_converter: getOption('url_converter'),
  26622. url_converter_scope: getOption('url_converter_scope'),
  26623. element_format: getOption('element_format'),
  26624. entities: getOption('entities'),
  26625. entity_encoding: getOption('entity_encoding'),
  26626. indent: getOption('indent'),
  26627. indent_after: getOption('indent_after'),
  26628. indent_before: getOption('indent_before')
  26629. })
  26630. };
  26631. };
  26632. const createParser = editor => {
  26633. const parser = DomParser(mkParserSettings(editor), editor.schema);
  26634. parser.addAttributeFilter('src,href,style,tabindex', (nodes, name) => {
  26635. const dom = editor.dom;
  26636. const internalName = 'data-mce-' + name;
  26637. let i = nodes.length;
  26638. while (i--) {
  26639. const node = nodes[i];
  26640. let value = node.attr(name);
  26641. if (value && !node.attr(internalName)) {
  26642. if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
  26643. continue;
  26644. }
  26645. if (name === 'style') {
  26646. value = dom.serializeStyle(dom.parseStyle(value), node.name);
  26647. if (!value.length) {
  26648. value = null;
  26649. }
  26650. node.attr(internalName, value);
  26651. node.attr(name, value);
  26652. } else if (name === 'tabindex') {
  26653. node.attr(internalName, value);
  26654. node.attr(name, null);
  26655. } else {
  26656. node.attr(internalName, editor.convertURL(value, name, node.name));
  26657. }
  26658. }
  26659. }
  26660. });
  26661. parser.addNodeFilter('script', nodes => {
  26662. let i = nodes.length;
  26663. while (i--) {
  26664. const node = nodes[i];
  26665. const type = node.attr('type') || 'no/type';
  26666. if (type.indexOf('mce-') !== 0) {
  26667. node.attr('type', 'mce-' + type);
  26668. }
  26669. }
  26670. });
  26671. if (shouldPreserveCData(editor)) {
  26672. parser.addNodeFilter('#cdata', nodes => {
  26673. var _a;
  26674. let i = nodes.length;
  26675. while (i--) {
  26676. const node = nodes[i];
  26677. node.type = 8;
  26678. node.name = '#comment';
  26679. node.value = '[CDATA[' + editor.dom.encode((_a = node.value) !== null && _a !== void 0 ? _a : '') + ']]';
  26680. }
  26681. });
  26682. }
  26683. parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', nodes => {
  26684. let i = nodes.length;
  26685. const nonEmptyElements = editor.schema.getNonEmptyElements();
  26686. while (i--) {
  26687. const node = nodes[i];
  26688. if (node.isEmpty(nonEmptyElements) && node.getAll('br').length === 0) {
  26689. node.append(new AstNode('br', 1));
  26690. }
  26691. }
  26692. });
  26693. return parser;
  26694. };
  26695. const autoFocus = editor => {
  26696. const autoFocus = getAutoFocus(editor);
  26697. if (autoFocus) {
  26698. Delay.setEditorTimeout(editor, () => {
  26699. let focusEditor;
  26700. if (autoFocus === true) {
  26701. focusEditor = editor;
  26702. } else {
  26703. focusEditor = editor.editorManager.get(autoFocus);
  26704. }
  26705. if (focusEditor && !focusEditor.destroyed) {
  26706. focusEditor.focus();
  26707. focusEditor.selection.scrollIntoView();
  26708. }
  26709. }, 100);
  26710. }
  26711. };
  26712. const moveSelectionToFirstCaretPosition = editor => {
  26713. const root = editor.dom.getRoot();
  26714. if (!editor.inline && (!hasAnyRanges(editor) || editor.selection.getStart(true) === root)) {
  26715. firstPositionIn(root).each(pos => {
  26716. const node = pos.getNode();
  26717. const caretPos = isTable$2(node) ? firstPositionIn(node).getOr(pos) : pos;
  26718. editor.selection.setRng(caretPos.toRange());
  26719. });
  26720. }
  26721. };
  26722. const initEditor = editor => {
  26723. editor.bindPendingEventDelegates();
  26724. editor.initialized = true;
  26725. fireInit(editor);
  26726. editor.focus(true);
  26727. moveSelectionToFirstCaretPosition(editor);
  26728. editor.nodeChanged({ initial: true });
  26729. const initInstanceCallback = getInitInstanceCallback(editor);
  26730. if (isFunction(initInstanceCallback)) {
  26731. initInstanceCallback.call(editor, editor);
  26732. }
  26733. autoFocus(editor);
  26734. };
  26735. const getStyleSheetLoader$1 = editor => editor.inline ? editor.ui.styleSheetLoader : editor.dom.styleSheetLoader;
  26736. const makeStylesheetLoadingPromises = (editor, css, framedFonts) => {
  26737. const promises = [getStyleSheetLoader$1(editor).loadAll(css)];
  26738. if (editor.inline) {
  26739. return promises;
  26740. } else {
  26741. return promises.concat([editor.ui.styleSheetLoader.loadAll(framedFonts)]);
  26742. }
  26743. };
  26744. const loadContentCss = editor => {
  26745. const styleSheetLoader = getStyleSheetLoader$1(editor);
  26746. const fontCss = getFontCss(editor);
  26747. const css = editor.contentCSS;
  26748. const removeCss = () => {
  26749. styleSheetLoader.unloadAll(css);
  26750. if (!editor.inline) {
  26751. editor.ui.styleSheetLoader.unloadAll(fontCss);
  26752. }
  26753. };
  26754. const loaded = () => {
  26755. if (editor.removed) {
  26756. removeCss();
  26757. } else {
  26758. editor.on('remove', removeCss);
  26759. }
  26760. };
  26761. if (editor.contentStyles.length > 0) {
  26762. let contentCssText = '';
  26763. Tools.each(editor.contentStyles, style => {
  26764. contentCssText += style + '\r\n';
  26765. });
  26766. editor.dom.addStyle(contentCssText);
  26767. }
  26768. const allStylesheets = Promise.all(makeStylesheetLoadingPromises(editor, css, fontCss)).then(loaded).catch(loaded);
  26769. const contentStyle = getContentStyle(editor);
  26770. if (contentStyle) {
  26771. appendStyle(editor, contentStyle);
  26772. }
  26773. return allStylesheets;
  26774. };
  26775. const preInit = editor => {
  26776. const doc = editor.getDoc(), body = editor.getBody();
  26777. firePreInit(editor);
  26778. if (!shouldBrowserSpellcheck(editor)) {
  26779. doc.body.spellcheck = false;
  26780. DOM$6.setAttrib(body, 'spellcheck', 'false');
  26781. }
  26782. editor.quirks = Quirks(editor);
  26783. firePostRender(editor);
  26784. const directionality = getDirectionality(editor);
  26785. if (directionality !== undefined) {
  26786. body.dir = directionality;
  26787. }
  26788. const protect = getProtect(editor);
  26789. if (protect) {
  26790. editor.on('BeforeSetContent', e => {
  26791. Tools.each(protect, pattern => {
  26792. e.content = e.content.replace(pattern, str => {
  26793. return '<!--mce:protected ' + escape(str) + '-->';
  26794. });
  26795. });
  26796. });
  26797. }
  26798. editor.on('SetContent', () => {
  26799. editor.addVisual(editor.getBody());
  26800. });
  26801. editor.on('compositionstart compositionend', e => {
  26802. editor.composing = e.type === 'compositionstart';
  26803. });
  26804. };
  26805. const loadInitialContent = editor => {
  26806. if (!isRtc(editor)) {
  26807. editor.load({
  26808. initial: true,
  26809. format: 'html'
  26810. });
  26811. }
  26812. editor.startContent = editor.getContent({ format: 'raw' });
  26813. };
  26814. const initEditorWithInitialContent = editor => {
  26815. if (editor.removed !== true) {
  26816. loadInitialContent(editor);
  26817. initEditor(editor);
  26818. }
  26819. };
  26820. const contentBodyLoaded = editor => {
  26821. const targetElm = editor.getElement();
  26822. let doc = editor.getDoc();
  26823. if (editor.inline) {
  26824. DOM$6.addClass(targetElm, 'mce-content-body');
  26825. editor.contentDocument = doc = document;
  26826. editor.contentWindow = window;
  26827. editor.bodyElement = targetElm;
  26828. editor.contentAreaContainer = targetElm;
  26829. }
  26830. const body = editor.getBody();
  26831. body.disabled = true;
  26832. editor.readonly = isReadOnly$1(editor);
  26833. if (!editor.readonly) {
  26834. if (editor.inline && DOM$6.getStyle(body, 'position', true) === 'static') {
  26835. body.style.position = 'relative';
  26836. }
  26837. body.contentEditable = 'true';
  26838. }
  26839. body.disabled = false;
  26840. editor.editorUpload = EditorUpload(editor);
  26841. editor.schema = Schema(mkSchemaSettings(editor));
  26842. editor.dom = DOMUtils(doc, {
  26843. keep_values: true,
  26844. url_converter: editor.convertURL,
  26845. url_converter_scope: editor,
  26846. update_styles: true,
  26847. root_element: editor.inline ? editor.getBody() : null,
  26848. collect: editor.inline,
  26849. schema: editor.schema,
  26850. contentCssCors: shouldUseContentCssCors(editor),
  26851. referrerPolicy: getReferrerPolicy(editor),
  26852. onSetAttrib: e => {
  26853. editor.dispatch('SetAttrib', e);
  26854. }
  26855. });
  26856. editor.parser = createParser(editor);
  26857. editor.serializer = DomSerializer(mkSerializerSettings(editor), editor);
  26858. editor.selection = EditorSelection(editor.dom, editor.getWin(), editor.serializer, editor);
  26859. editor.annotator = Annotator(editor);
  26860. editor.formatter = Formatter(editor);
  26861. editor.undoManager = UndoManager(editor);
  26862. editor._nodeChangeDispatcher = new NodeChange(editor);
  26863. editor._selectionOverrides = SelectionOverrides(editor);
  26864. setup$o(editor);
  26865. setup$6(editor);
  26866. setup$m(editor);
  26867. if (!isRtc(editor)) {
  26868. setup$5(editor);
  26869. setup$1(editor);
  26870. }
  26871. const caret = setup$b(editor);
  26872. setup$p(editor, caret);
  26873. setup$n(editor);
  26874. setup$q(editor);
  26875. setup$7(editor);
  26876. const setupRtcThunk = setup$s(editor);
  26877. preInit(editor);
  26878. setupRtcThunk.fold(() => {
  26879. loadContentCss(editor).then(() => initEditorWithInitialContent(editor));
  26880. }, setupRtc => {
  26881. editor.setProgressState(true);
  26882. loadContentCss(editor).then(() => {
  26883. setupRtc().then(_rtcMode => {
  26884. editor.setProgressState(false);
  26885. initEditorWithInitialContent(editor);
  26886. bindEvents(editor);
  26887. }, err => {
  26888. editor.notificationManager.open({
  26889. type: 'error',
  26890. text: String(err)
  26891. });
  26892. initEditorWithInitialContent(editor);
  26893. bindEvents(editor);
  26894. });
  26895. });
  26896. });
  26897. };
  26898. const initContentBody = (editor, skipWrite) => {
  26899. if (!editor.inline) {
  26900. editor.getElement().style.visibility = editor.orgVisibility;
  26901. }
  26902. if (!skipWrite && !editor.inline) {
  26903. const iframe = editor.iframeElement;
  26904. const binder = bind$1(SugarElement.fromDom(iframe), 'load', () => {
  26905. binder.unbind();
  26906. editor.contentDocument = iframe.contentDocument;
  26907. contentBodyLoaded(editor);
  26908. });
  26909. if (Env.browser.isFirefox()) {
  26910. const doc = editor.getDoc();
  26911. doc.open();
  26912. doc.write(editor.iframeHTML);
  26913. doc.close();
  26914. } else {
  26915. iframe.srcdoc = editor.iframeHTML;
  26916. }
  26917. } else {
  26918. contentBodyLoaded(editor);
  26919. }
  26920. };
  26921. const DOM$5 = DOMUtils.DOM;
  26922. const createIframeElement = (id, title, customAttrs, tabindex) => {
  26923. const iframe = SugarElement.fromTag('iframe');
  26924. tabindex.each(t => set$2(iframe, 'tabindex', t));
  26925. setAll$1(iframe, customAttrs);
  26926. setAll$1(iframe, {
  26927. id: id + '_ifr',
  26928. frameBorder: '0',
  26929. allowTransparency: 'true',
  26930. title
  26931. });
  26932. add$2(iframe, 'tox-edit-area__iframe');
  26933. return iframe;
  26934. };
  26935. const getIframeHtml = editor => {
  26936. let iframeHTML = getDocType(editor) + '<html><head>';
  26937. if (getDocumentBaseUrl(editor) !== editor.documentBaseUrl) {
  26938. iframeHTML += '<base href="' + editor.documentBaseURI.getURI() + '" />';
  26939. }
  26940. iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
  26941. const bodyId = getBodyId(editor);
  26942. const bodyClass = getBodyClass(editor);
  26943. const translatedAriaText = editor.translate(getIframeAriaText(editor));
  26944. if (getContentSecurityPolicy(editor)) {
  26945. iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + getContentSecurityPolicy(editor) + '" />';
  26946. }
  26947. iframeHTML += '</head>' + `<body id="${ bodyId }" class="mce-content-body ${ bodyClass }" data-id="${ editor.id }" aria-label="${ translatedAriaText }">` + '<br>' + '</body></html>';
  26948. return iframeHTML;
  26949. };
  26950. const createIframe = (editor, boxInfo) => {
  26951. const iframeTitle = editor.translate('Rich Text Area');
  26952. const tabindex = getOpt(SugarElement.fromDom(editor.getElement()), 'tabindex').bind(toInt);
  26953. const ifr = createIframeElement(editor.id, iframeTitle, getIframeAttrs(editor), tabindex).dom;
  26954. ifr.onload = () => {
  26955. ifr.onload = null;
  26956. editor.dispatch('load');
  26957. };
  26958. editor.contentAreaContainer = boxInfo.iframeContainer;
  26959. editor.iframeElement = ifr;
  26960. editor.iframeHTML = getIframeHtml(editor);
  26961. DOM$5.add(boxInfo.iframeContainer, ifr);
  26962. };
  26963. const init$1 = (editor, boxInfo) => {
  26964. createIframe(editor, boxInfo);
  26965. if (boxInfo.editorContainer) {
  26966. boxInfo.editorContainer.style.display = editor.orgDisplay;
  26967. editor.hidden = DOM$5.isHidden(boxInfo.editorContainer);
  26968. }
  26969. editor.getElement().style.display = 'none';
  26970. DOM$5.setAttrib(editor.id, 'aria-hidden', 'true');
  26971. initContentBody(editor);
  26972. };
  26973. const DOM$4 = DOMUtils.DOM;
  26974. const initPlugin = (editor, initializedPlugins, plugin) => {
  26975. const Plugin = PluginManager.get(plugin);
  26976. const pluginUrl = PluginManager.urls[plugin] || editor.documentBaseUrl.replace(/\/$/, '');
  26977. plugin = Tools.trim(plugin);
  26978. if (Plugin && Tools.inArray(initializedPlugins, plugin) === -1) {
  26979. if (editor.plugins[plugin]) {
  26980. return;
  26981. }
  26982. try {
  26983. const pluginInstance = Plugin(editor, pluginUrl) || {};
  26984. editor.plugins[plugin] = pluginInstance;
  26985. if (isFunction(pluginInstance.init)) {
  26986. pluginInstance.init(editor, pluginUrl);
  26987. initializedPlugins.push(plugin);
  26988. }
  26989. } catch (e) {
  26990. pluginInitError(editor, plugin, e);
  26991. }
  26992. }
  26993. };
  26994. const trimLegacyPrefix = name => {
  26995. return name.replace(/^\-/, '');
  26996. };
  26997. const initPlugins = editor => {
  26998. const initializedPlugins = [];
  26999. each$e(getPlugins(editor), name => {
  27000. initPlugin(editor, initializedPlugins, trimLegacyPrefix(name));
  27001. });
  27002. };
  27003. const initIcons = editor => {
  27004. const iconPackName = Tools.trim(getIconPackName(editor));
  27005. const currentIcons = editor.ui.registry.getAll().icons;
  27006. const loadIcons = {
  27007. ...IconManager.get('default').icons,
  27008. ...IconManager.get(iconPackName).icons
  27009. };
  27010. each$d(loadIcons, (svgData, icon) => {
  27011. if (!has$2(currentIcons, icon)) {
  27012. editor.ui.registry.addIcon(icon, svgData);
  27013. }
  27014. });
  27015. };
  27016. const initTheme = editor => {
  27017. const theme = getTheme(editor);
  27018. if (isString(theme)) {
  27019. const Theme = ThemeManager.get(theme);
  27020. editor.theme = Theme(editor, ThemeManager.urls[theme]) || {};
  27021. if (isFunction(editor.theme.init)) {
  27022. editor.theme.init(editor, ThemeManager.urls[theme] || editor.documentBaseUrl.replace(/\/$/, ''));
  27023. }
  27024. } else {
  27025. editor.theme = {};
  27026. }
  27027. };
  27028. const initModel = editor => {
  27029. const model = getModel(editor);
  27030. const Model = ModelManager.get(model);
  27031. editor.model = Model(editor, ModelManager.urls[model]);
  27032. };
  27033. const renderFromLoadedTheme = editor => {
  27034. const render = editor.theme.renderUI;
  27035. return render ? render() : renderThemeFalse(editor);
  27036. };
  27037. const renderFromThemeFunc = editor => {
  27038. const elm = editor.getElement();
  27039. const theme = getTheme(editor);
  27040. const info = theme(editor, elm);
  27041. if (info.editorContainer.nodeType) {
  27042. info.editorContainer.id = info.editorContainer.id || editor.id + '_parent';
  27043. }
  27044. if (info.iframeContainer && info.iframeContainer.nodeType) {
  27045. info.iframeContainer.id = info.iframeContainer.id || editor.id + '_iframecontainer';
  27046. }
  27047. info.height = info.iframeHeight ? info.iframeHeight : elm.offsetHeight;
  27048. return info;
  27049. };
  27050. const createThemeFalseResult = (element, iframe) => {
  27051. return {
  27052. editorContainer: element,
  27053. iframeContainer: iframe,
  27054. api: {}
  27055. };
  27056. };
  27057. const renderThemeFalseIframe = targetElement => {
  27058. const iframeContainer = DOM$4.create('div');
  27059. DOM$4.insertAfter(iframeContainer, targetElement);
  27060. return createThemeFalseResult(iframeContainer, iframeContainer);
  27061. };
  27062. const renderThemeFalse = editor => {
  27063. const targetElement = editor.getElement();
  27064. return editor.inline ? createThemeFalseResult(null) : renderThemeFalseIframe(targetElement);
  27065. };
  27066. const renderThemeUi = editor => {
  27067. const elm = editor.getElement();
  27068. editor.orgDisplay = elm.style.display;
  27069. if (isString(getTheme(editor))) {
  27070. return renderFromLoadedTheme(editor);
  27071. } else if (isFunction(getTheme(editor))) {
  27072. return renderFromThemeFunc(editor);
  27073. } else {
  27074. return renderThemeFalse(editor);
  27075. }
  27076. };
  27077. const augmentEditorUiApi = (editor, api) => {
  27078. const uiApiFacade = {
  27079. show: Optional.from(api.show).getOr(noop),
  27080. hide: Optional.from(api.hide).getOr(noop),
  27081. isEnabled: Optional.from(api.isEnabled).getOr(always),
  27082. setEnabled: state => {
  27083. if (!editor.mode.isReadOnly()) {
  27084. Optional.from(api.setEnabled).each(f => f(state));
  27085. }
  27086. }
  27087. };
  27088. editor.ui = {
  27089. ...editor.ui,
  27090. ...uiApiFacade
  27091. };
  27092. };
  27093. const init = editor => {
  27094. editor.dispatch('ScriptsLoaded');
  27095. initIcons(editor);
  27096. initTheme(editor);
  27097. initModel(editor);
  27098. initPlugins(editor);
  27099. const renderInfo = renderThemeUi(editor);
  27100. augmentEditorUiApi(editor, Optional.from(renderInfo.api).getOr({}));
  27101. editor.editorContainer = renderInfo.editorContainer;
  27102. appendContentCssFromSettings(editor);
  27103. if (editor.inline) {
  27104. initContentBody(editor);
  27105. } else {
  27106. init$1(editor, {
  27107. editorContainer: renderInfo.editorContainer,
  27108. iframeContainer: renderInfo.iframeContainer
  27109. });
  27110. }
  27111. };
  27112. const DOM$3 = DOMUtils.DOM;
  27113. const hasSkipLoadPrefix = name => name.charAt(0) === '-';
  27114. const loadLanguage = (scriptLoader, editor) => {
  27115. const languageCode = getLanguageCode(editor);
  27116. const languageUrl = getLanguageUrl(editor);
  27117. if (!I18n.hasCode(languageCode) && languageCode !== 'en') {
  27118. const url = isNotEmpty(languageUrl) ? languageUrl : `${ editor.editorManager.baseURL }/langs/${ languageCode }.js`;
  27119. scriptLoader.add(url).catch(() => {
  27120. languageLoadError(editor, url, languageCode);
  27121. });
  27122. }
  27123. };
  27124. const loadTheme = (editor, suffix) => {
  27125. const theme = getTheme(editor);
  27126. if (isString(theme) && !hasSkipLoadPrefix(theme) && !has$2(ThemeManager.urls, theme)) {
  27127. const themeUrl = getThemeUrl(editor);
  27128. const url = themeUrl ? editor.documentBaseURI.toAbsolute(themeUrl) : `themes/${ theme }/theme${ suffix }.js`;
  27129. ThemeManager.load(theme, url).catch(() => {
  27130. themeLoadError(editor, url, theme);
  27131. });
  27132. }
  27133. };
  27134. const loadModel = (editor, suffix) => {
  27135. const model = getModel(editor);
  27136. if (model !== 'plugin' && !has$2(ModelManager.urls, model)) {
  27137. const modelUrl = getModelUrl(editor);
  27138. const url = isString(modelUrl) ? editor.documentBaseURI.toAbsolute(modelUrl) : `models/${ model }/model${ suffix }.js`;
  27139. ModelManager.load(model, url).catch(() => {
  27140. modelLoadError(editor, url, model);
  27141. });
  27142. }
  27143. };
  27144. const getIconsUrlMetaFromUrl = editor => Optional.from(getIconsUrl(editor)).filter(isNotEmpty).map(url => ({
  27145. url,
  27146. name: Optional.none()
  27147. }));
  27148. const getIconsUrlMetaFromName = (editor, name, suffix) => Optional.from(name).filter(name => isNotEmpty(name) && !IconManager.has(name)).map(name => ({
  27149. url: `${ editor.editorManager.baseURL }/icons/${ name }/icons${ suffix }.js`,
  27150. name: Optional.some(name)
  27151. }));
  27152. const loadIcons = (scriptLoader, editor, suffix) => {
  27153. const defaultIconsUrl = getIconsUrlMetaFromName(editor, 'default', suffix);
  27154. const customIconsUrl = getIconsUrlMetaFromUrl(editor).orThunk(() => getIconsUrlMetaFromName(editor, getIconPackName(editor), ''));
  27155. each$e(cat([
  27156. defaultIconsUrl,
  27157. customIconsUrl
  27158. ]), urlMeta => {
  27159. scriptLoader.add(urlMeta.url).catch(() => {
  27160. iconsLoadError(editor, urlMeta.url, urlMeta.name.getOrUndefined());
  27161. });
  27162. });
  27163. };
  27164. const loadPlugins = (editor, suffix) => {
  27165. const loadPlugin = (name, url) => {
  27166. PluginManager.load(name, url).catch(() => {
  27167. pluginLoadError(editor, url, name);
  27168. });
  27169. };
  27170. each$d(getExternalPlugins$1(editor), (url, name) => {
  27171. loadPlugin(name, url);
  27172. editor.options.set('plugins', getPlugins(editor).concat(name));
  27173. });
  27174. each$e(getPlugins(editor), plugin => {
  27175. plugin = Tools.trim(plugin);
  27176. if (plugin && !PluginManager.urls[plugin] && !hasSkipLoadPrefix(plugin)) {
  27177. loadPlugin(plugin, `plugins/${ plugin }/plugin${ suffix }.js`);
  27178. }
  27179. });
  27180. };
  27181. const isThemeLoaded = editor => {
  27182. const theme = getTheme(editor);
  27183. return !isString(theme) || isNonNullable(ThemeManager.get(theme));
  27184. };
  27185. const isModelLoaded = editor => {
  27186. const model = getModel(editor);
  27187. return isNonNullable(ModelManager.get(model));
  27188. };
  27189. const loadScripts = (editor, suffix) => {
  27190. const scriptLoader = ScriptLoader.ScriptLoader;
  27191. const initEditor = () => {
  27192. if (!editor.removed && isThemeLoaded(editor) && isModelLoaded(editor)) {
  27193. init(editor);
  27194. }
  27195. };
  27196. loadTheme(editor, suffix);
  27197. loadModel(editor, suffix);
  27198. loadLanguage(scriptLoader, editor);
  27199. loadIcons(scriptLoader, editor, suffix);
  27200. loadPlugins(editor, suffix);
  27201. scriptLoader.loadQueue().then(initEditor, initEditor);
  27202. };
  27203. const getStyleSheetLoader = (element, editor) => instance.forElement(element, {
  27204. contentCssCors: hasContentCssCors(editor),
  27205. referrerPolicy: getReferrerPolicy(editor)
  27206. });
  27207. const render = editor => {
  27208. const id = editor.id;
  27209. I18n.setCode(getLanguageCode(editor));
  27210. const readyHandler = () => {
  27211. DOM$3.unbind(window, 'ready', readyHandler);
  27212. editor.render();
  27213. };
  27214. if (!EventUtils.Event.domLoaded) {
  27215. DOM$3.bind(window, 'ready', readyHandler);
  27216. return;
  27217. }
  27218. if (!editor.getElement()) {
  27219. return;
  27220. }
  27221. const element = SugarElement.fromDom(editor.getElement());
  27222. const snapshot = clone$4(element);
  27223. editor.on('remove', () => {
  27224. eachr(element.dom.attributes, attr => remove$b(element, attr.name));
  27225. setAll$1(element, snapshot);
  27226. });
  27227. editor.ui.styleSheetLoader = getStyleSheetLoader(element, editor);
  27228. if (!isInline(editor)) {
  27229. editor.orgVisibility = editor.getElement().style.visibility;
  27230. editor.getElement().style.visibility = 'hidden';
  27231. } else {
  27232. editor.inline = true;
  27233. }
  27234. const form = editor.getElement().form || DOM$3.getParent(id, 'form');
  27235. if (form) {
  27236. editor.formElement = form;
  27237. if (hasHiddenInput(editor) && !isTextareaOrInput(editor.getElement())) {
  27238. DOM$3.insertAfter(DOM$3.create('input', {
  27239. type: 'hidden',
  27240. name: id
  27241. }), id);
  27242. editor.hasHiddenInput = true;
  27243. }
  27244. editor.formEventDelegate = e => {
  27245. editor.dispatch(e.type, e);
  27246. };
  27247. DOM$3.bind(form, 'submit reset', editor.formEventDelegate);
  27248. editor.on('reset', () => {
  27249. editor.resetContent();
  27250. });
  27251. if (shouldPatchSubmit(editor) && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
  27252. form._mceOldSubmit = form.submit;
  27253. form.submit = () => {
  27254. editor.editorManager.triggerSave();
  27255. editor.setDirty(false);
  27256. return form._mceOldSubmit(form);
  27257. };
  27258. }
  27259. }
  27260. editor.windowManager = WindowManager(editor);
  27261. editor.notificationManager = NotificationManager(editor);
  27262. if (isEncodingXml(editor)) {
  27263. editor.on('GetContent', e => {
  27264. if (e.save) {
  27265. e.content = DOM$3.encode(e.content);
  27266. }
  27267. });
  27268. }
  27269. if (shouldAddFormSubmitTrigger(editor)) {
  27270. editor.on('submit', () => {
  27271. if (editor.initialized) {
  27272. editor.save();
  27273. }
  27274. });
  27275. }
  27276. if (shouldAddUnloadTrigger(editor)) {
  27277. editor._beforeUnload = () => {
  27278. if (editor.initialized && !editor.destroyed && !editor.isHidden()) {
  27279. editor.save({
  27280. format: 'raw',
  27281. no_events: true,
  27282. set_dirty: false
  27283. });
  27284. }
  27285. };
  27286. editor.editorManager.on('BeforeUnload', editor._beforeUnload);
  27287. }
  27288. editor.editorManager.add(editor);
  27289. loadScripts(editor, editor.suffix);
  27290. };
  27291. const sectionResult = (sections, settings) => ({
  27292. sections: constant(sections),
  27293. options: constant(settings)
  27294. });
  27295. const deviceDetection = detect$2().deviceType;
  27296. const isPhone = deviceDetection.isPhone();
  27297. const isTablet = deviceDetection.isTablet();
  27298. const normalizePlugins = plugins => {
  27299. if (isNullable(plugins)) {
  27300. return [];
  27301. } else {
  27302. const pluginNames = isArray$1(plugins) ? plugins : plugins.split(/[ ,]/);
  27303. const trimmedPlugins = map$3(pluginNames, trim$3);
  27304. return filter$5(trimmedPlugins, isNotEmpty);
  27305. }
  27306. };
  27307. const extractSections = (keys, options) => {
  27308. const result = bifilter(options, (value, key) => {
  27309. return contains$2(keys, key);
  27310. });
  27311. return sectionResult(result.t, result.f);
  27312. };
  27313. const getSection = (sectionResult, name, defaults = {}) => {
  27314. const sections = sectionResult.sections();
  27315. const sectionOptions = get$a(sections, name).getOr({});
  27316. return Tools.extend({}, defaults, sectionOptions);
  27317. };
  27318. const hasSection = (sectionResult, name) => {
  27319. return has$2(sectionResult.sections(), name);
  27320. };
  27321. const getSectionConfig = (sectionResult, name) => {
  27322. return hasSection(sectionResult, name) ? sectionResult.sections()[name] : {};
  27323. };
  27324. const getMobileOverrideOptions = (mobileOptions, isPhone) => {
  27325. const defaultMobileOptions = {
  27326. table_grid: false,
  27327. object_resizing: false,
  27328. resize: false,
  27329. toolbar_mode: get$a(mobileOptions, 'toolbar_mode').getOr('scrolling'),
  27330. toolbar_sticky: false
  27331. };
  27332. const defaultPhoneOptions = { menubar: false };
  27333. return {
  27334. ...defaultMobileOptions,
  27335. ...isPhone ? defaultPhoneOptions : {}
  27336. };
  27337. };
  27338. const getExternalPlugins = (overrideOptions, options) => {
  27339. var _a;
  27340. const userDefinedExternalPlugins = (_a = options.external_plugins) !== null && _a !== void 0 ? _a : {};
  27341. if (overrideOptions && overrideOptions.external_plugins) {
  27342. return Tools.extend({}, overrideOptions.external_plugins, userDefinedExternalPlugins);
  27343. } else {
  27344. return userDefinedExternalPlugins;
  27345. }
  27346. };
  27347. const combinePlugins = (forcedPlugins, plugins) => [
  27348. ...normalizePlugins(forcedPlugins),
  27349. ...normalizePlugins(plugins)
  27350. ];
  27351. const getPlatformPlugins = (isMobileDevice, sectionResult, desktopPlugins, mobilePlugins) => {
  27352. if (isMobileDevice && hasSection(sectionResult, 'mobile')) {
  27353. return mobilePlugins;
  27354. } else {
  27355. return desktopPlugins;
  27356. }
  27357. };
  27358. const processPlugins = (isMobileDevice, sectionResult, defaultOverrideOptions, options) => {
  27359. const forcedPlugins = normalizePlugins(defaultOverrideOptions.forced_plugins);
  27360. const desktopPlugins = normalizePlugins(options.plugins);
  27361. const mobileConfig = getSectionConfig(sectionResult, 'mobile');
  27362. const mobilePlugins = mobileConfig.plugins ? normalizePlugins(mobileConfig.plugins) : desktopPlugins;
  27363. const platformPlugins = getPlatformPlugins(isMobileDevice, sectionResult, desktopPlugins, mobilePlugins);
  27364. const combinedPlugins = combinePlugins(forcedPlugins, platformPlugins);
  27365. return Tools.extend(options, {
  27366. forced_plugins: forcedPlugins,
  27367. plugins: combinedPlugins
  27368. });
  27369. };
  27370. const isOnMobile = (isMobileDevice, sectionResult) => {
  27371. return isMobileDevice && hasSection(sectionResult, 'mobile');
  27372. };
  27373. const combineOptions = (isMobileDevice, isPhone, defaultOptions, defaultOverrideOptions, options) => {
  27374. var _a;
  27375. const deviceOverrideOptions = isMobileDevice ? { mobile: getMobileOverrideOptions((_a = options.mobile) !== null && _a !== void 0 ? _a : {}, isPhone) } : {};
  27376. const sectionResult = extractSections(['mobile'], deepMerge(deviceOverrideOptions, options));
  27377. const extendedOptions = Tools.extend(defaultOptions, defaultOverrideOptions, sectionResult.options(), isOnMobile(isMobileDevice, sectionResult) ? getSection(sectionResult, 'mobile') : {}, { external_plugins: getExternalPlugins(defaultOverrideOptions, sectionResult.options()) });
  27378. return processPlugins(isMobileDevice, sectionResult, defaultOverrideOptions, extendedOptions);
  27379. };
  27380. const normalizeOptions = (defaultOverrideOptions, options) => combineOptions(isPhone || isTablet, isPhone, options, defaultOverrideOptions, options);
  27381. const addVisual = (editor, elm) => addVisual$1(editor, elm);
  27382. const registerExecCommands$3 = editor => {
  27383. const toggleFormat = (name, value) => {
  27384. editor.formatter.toggle(name, value);
  27385. editor.nodeChanged();
  27386. };
  27387. const toggleAlign = align => () => {
  27388. each$e('left,center,right,justify'.split(','), name => {
  27389. if (align !== name) {
  27390. editor.formatter.remove('align' + name);
  27391. }
  27392. });
  27393. if (align !== 'none') {
  27394. toggleFormat('align' + align);
  27395. }
  27396. };
  27397. editor.editorCommands.addCommands({
  27398. JustifyLeft: toggleAlign('left'),
  27399. JustifyCenter: toggleAlign('center'),
  27400. JustifyRight: toggleAlign('right'),
  27401. JustifyFull: toggleAlign('justify'),
  27402. JustifyNone: toggleAlign('none')
  27403. });
  27404. };
  27405. const registerQueryStateCommands$1 = editor => {
  27406. const alignStates = name => () => {
  27407. const selection = editor.selection;
  27408. const nodes = selection.isCollapsed() ? [editor.dom.getParent(selection.getNode(), editor.dom.isBlock)] : selection.getSelectedBlocks();
  27409. return exists(nodes, node => isNonNullable(editor.formatter.matchNode(node, name)));
  27410. };
  27411. editor.editorCommands.addCommands({
  27412. JustifyLeft: alignStates('alignleft'),
  27413. JustifyCenter: alignStates('aligncenter'),
  27414. JustifyRight: alignStates('alignright'),
  27415. JustifyFull: alignStates('alignjustify')
  27416. }, 'state');
  27417. };
  27418. const registerCommands$a = editor => {
  27419. registerExecCommands$3(editor);
  27420. registerQueryStateCommands$1(editor);
  27421. };
  27422. const registerCommands$9 = editor => {
  27423. editor.editorCommands.addCommands({
  27424. 'Cut,Copy,Paste': command => {
  27425. const doc = editor.getDoc();
  27426. let failed;
  27427. try {
  27428. doc.execCommand(command);
  27429. } catch (ex) {
  27430. failed = true;
  27431. }
  27432. if (command === 'paste' && !doc.queryCommandEnabled(command)) {
  27433. failed = true;
  27434. }
  27435. if (failed || !doc.queryCommandSupported(command)) {
  27436. let msg = editor.translate(`Your browser doesn't support direct access to the clipboard. ` + 'Please use the Ctrl+X/C/V keyboard shortcuts instead.');
  27437. if (Env.os.isMacOS() || Env.os.isiOS()) {
  27438. msg = msg.replace(/Ctrl\+/g, '\u2318+');
  27439. }
  27440. editor.notificationManager.open({
  27441. text: msg,
  27442. type: 'error'
  27443. });
  27444. }
  27445. }
  27446. });
  27447. };
  27448. const trimOrPadLeftRight = (dom, rng, html) => {
  27449. const root = SugarElement.fromDom(dom.getRoot());
  27450. if (needsToBeNbspLeft(root, CaretPosition.fromRangeStart(rng))) {
  27451. html = html.replace(/^ /, '&nbsp;');
  27452. } else {
  27453. html = html.replace(/^&nbsp;/, ' ');
  27454. }
  27455. if (needsToBeNbspRight(root, CaretPosition.fromRangeEnd(rng))) {
  27456. html = html.replace(/(&nbsp;| )(<br( \/)>)?$/, '&nbsp;');
  27457. } else {
  27458. html = html.replace(/&nbsp;(<br( \/)?>)?$/, ' ');
  27459. }
  27460. return html;
  27461. };
  27462. const processValue$1 = value => {
  27463. if (typeof value !== 'string') {
  27464. const details = Tools.extend({
  27465. paste: value.paste,
  27466. data: { paste: value.paste }
  27467. }, value);
  27468. return {
  27469. content: value.content,
  27470. details
  27471. };
  27472. }
  27473. return {
  27474. content: value,
  27475. details: {}
  27476. };
  27477. };
  27478. const trimOrPad = (editor, value) => {
  27479. const selection = editor.selection;
  27480. const dom = editor.dom;
  27481. if (/^ | $/.test(value)) {
  27482. return trimOrPadLeftRight(dom, selection.getRng(), value);
  27483. } else {
  27484. return value;
  27485. }
  27486. };
  27487. const insertAtCaret = (editor, value) => {
  27488. const {content, details} = processValue$1(value);
  27489. preProcessSetContent(editor, {
  27490. ...details,
  27491. content: trimOrPad(editor, content),
  27492. format: 'html',
  27493. set: false,
  27494. selection: true
  27495. }).each(args => {
  27496. const insertedContent = insertContent$1(editor, args.content, details);
  27497. postProcessSetContent(editor, insertedContent, args);
  27498. editor.addVisual();
  27499. });
  27500. };
  27501. const registerCommands$8 = editor => {
  27502. editor.editorCommands.addCommands({
  27503. mceCleanup: () => {
  27504. const bm = editor.selection.getBookmark();
  27505. editor.setContent(editor.getContent());
  27506. editor.selection.moveToBookmark(bm);
  27507. },
  27508. insertImage: (_command, _ui, value) => {
  27509. insertAtCaret(editor, editor.dom.createHTML('img', { src: value }));
  27510. },
  27511. insertHorizontalRule: () => {
  27512. editor.execCommand('mceInsertContent', false, '<hr>');
  27513. },
  27514. insertText: (_command, _ui, value) => {
  27515. insertAtCaret(editor, editor.dom.encode(value));
  27516. },
  27517. insertHTML: (_command, _ui, value) => {
  27518. insertAtCaret(editor, value);
  27519. },
  27520. mceInsertContent: (_command, _ui, value) => {
  27521. insertAtCaret(editor, value);
  27522. },
  27523. mceSetContent: (_command, _ui, value) => {
  27524. editor.setContent(value);
  27525. },
  27526. mceReplaceContent: (_command, _ui, value) => {
  27527. editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, editor.selection.getContent({ format: 'text' })));
  27528. },
  27529. mceNewDocument: () => {
  27530. editor.setContent('');
  27531. }
  27532. });
  27533. };
  27534. const legacyPropNames = {
  27535. 'font-size': 'size',
  27536. 'font-family': 'face'
  27537. };
  27538. const isFont = isTag('font');
  27539. const getSpecifiedFontProp = (propName, rootElm, elm) => {
  27540. const getProperty = elm => getRaw$1(elm, propName).orThunk(() => {
  27541. if (isFont(elm)) {
  27542. return get$a(legacyPropNames, propName).bind(legacyPropName => getOpt(elm, legacyPropName));
  27543. } else {
  27544. return Optional.none();
  27545. }
  27546. });
  27547. const isRoot = elm => eq(SugarElement.fromDom(rootElm), elm);
  27548. return closest$2(SugarElement.fromDom(elm), elm => getProperty(elm), isRoot);
  27549. };
  27550. const normalizeFontFamily = fontFamily => fontFamily.replace(/[\'\"\\]/g, '').replace(/,\s+/g, ',');
  27551. const getComputedFontProp = (propName, elm) => Optional.from(DOMUtils.DOM.getStyle(elm, propName, true));
  27552. const getFontProp = propName => (rootElm, elm) => Optional.from(elm).map(SugarElement.fromDom).filter(isElement$7).bind(element => getSpecifiedFontProp(propName, rootElm, element.dom).or(getComputedFontProp(propName, element.dom))).getOr('');
  27553. const getFontSize = getFontProp('font-size');
  27554. const getFontFamily = compose(normalizeFontFamily, getFontProp('font-family'));
  27555. const findFirstCaretElement = editor => firstPositionIn(editor.getBody()).bind(caret => {
  27556. const container = caret.container();
  27557. return Optional.from(isText$a(container) ? container.parentNode : container);
  27558. });
  27559. const getCaretElement = editor => Optional.from(editor.selection.getRng()).bind(rng => {
  27560. const root = editor.getBody();
  27561. const atStartOfNode = rng.startContainer === root && rng.startOffset === 0;
  27562. return atStartOfNode ? Optional.none() : Optional.from(editor.selection.getStart(true));
  27563. });
  27564. const bindRange = (editor, binder) => getCaretElement(editor).orThunk(curry(findFirstCaretElement, editor)).map(SugarElement.fromDom).filter(isElement$7).bind(binder);
  27565. const mapRange = (editor, mapper) => bindRange(editor, compose1(Optional.some, mapper));
  27566. const fromFontSizeNumber = (editor, value) => {
  27567. if (/^[0-9.]+$/.test(value)) {
  27568. const fontSizeNumber = parseInt(value, 10);
  27569. if (fontSizeNumber >= 1 && fontSizeNumber <= 7) {
  27570. const fontSizes = getFontStyleValues(editor);
  27571. const fontClasses = getFontSizeClasses(editor);
  27572. if (fontClasses.length > 0) {
  27573. return fontClasses[fontSizeNumber - 1] || value;
  27574. } else {
  27575. return fontSizes[fontSizeNumber - 1] || value;
  27576. }
  27577. } else {
  27578. return value;
  27579. }
  27580. } else {
  27581. return value;
  27582. }
  27583. };
  27584. const normalizeFontNames = font => {
  27585. const fonts = font.split(/\s*,\s*/);
  27586. return map$3(fonts, font => {
  27587. if (font.indexOf(' ') !== -1 && !(startsWith(font, '"') || startsWith(font, `'`))) {
  27588. return `'${ font }'`;
  27589. } else {
  27590. return font;
  27591. }
  27592. }).join(',');
  27593. };
  27594. const fontNameAction = (editor, value) => {
  27595. const font = fromFontSizeNumber(editor, value);
  27596. editor.formatter.toggle('fontname', { value: normalizeFontNames(font) });
  27597. editor.nodeChanged();
  27598. };
  27599. const fontNameQuery = editor => mapRange(editor, elm => getFontFamily(editor.getBody(), elm.dom)).getOr('');
  27600. const fontSizeAction = (editor, value) => {
  27601. editor.formatter.toggle('fontsize', { value: fromFontSizeNumber(editor, value) });
  27602. editor.nodeChanged();
  27603. };
  27604. const fontSizeQuery = editor => mapRange(editor, elm => getFontSize(editor.getBody(), elm.dom)).getOr('');
  27605. const lineHeightQuery = editor => mapRange(editor, elm => {
  27606. const root = SugarElement.fromDom(editor.getBody());
  27607. const specifiedStyle = closest$2(elm, elm => getRaw$1(elm, 'line-height'), curry(eq, root));
  27608. const computedStyle = () => {
  27609. const lineHeight = parseFloat(get$7(elm, 'line-height'));
  27610. const fontSize = parseFloat(get$7(elm, 'font-size'));
  27611. return String(lineHeight / fontSize);
  27612. };
  27613. return specifiedStyle.getOrThunk(computedStyle);
  27614. }).getOr('');
  27615. const lineHeightAction = (editor, lineHeight) => {
  27616. editor.formatter.toggle('lineheight', { value: String(lineHeight) });
  27617. editor.nodeChanged();
  27618. };
  27619. const registerExecCommands$2 = editor => {
  27620. const toggleFormat = (name, value) => {
  27621. editor.formatter.toggle(name, value);
  27622. editor.nodeChanged();
  27623. };
  27624. editor.editorCommands.addCommands({
  27625. 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => {
  27626. toggleFormat(command);
  27627. },
  27628. 'ForeColor,HiliteColor': (command, _ui, value) => {
  27629. toggleFormat(command, { value });
  27630. },
  27631. 'BackColor': (_command, _ui, value) => {
  27632. toggleFormat('hilitecolor', { value });
  27633. },
  27634. 'FontName': (_command, _ui, value) => {
  27635. fontNameAction(editor, value);
  27636. },
  27637. 'FontSize': (_command, _ui, value) => {
  27638. fontSizeAction(editor, value);
  27639. },
  27640. 'LineHeight': (_command, _ui, value) => {
  27641. lineHeightAction(editor, value);
  27642. },
  27643. 'Lang': (command, _ui, lang) => {
  27644. var _a;
  27645. toggleFormat(command, {
  27646. value: lang.code,
  27647. customValue: (_a = lang.customCode) !== null && _a !== void 0 ? _a : null
  27648. });
  27649. },
  27650. 'RemoveFormat': command => {
  27651. editor.formatter.remove(command);
  27652. },
  27653. 'mceBlockQuote': () => {
  27654. toggleFormat('blockquote');
  27655. },
  27656. 'FormatBlock': (_command, _ui, value) => {
  27657. toggleFormat(isString(value) ? value : 'p');
  27658. },
  27659. 'mceToggleFormat': (_command, _ui, value) => {
  27660. toggleFormat(value);
  27661. }
  27662. });
  27663. };
  27664. const registerQueryValueCommands = editor => {
  27665. const isFormatMatch = name => editor.formatter.match(name);
  27666. editor.editorCommands.addCommands({
  27667. 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript': command => isFormatMatch(command),
  27668. 'mceBlockQuote': () => isFormatMatch('blockquote')
  27669. }, 'state');
  27670. editor.editorCommands.addQueryValueHandler('FontName', () => fontNameQuery(editor));
  27671. editor.editorCommands.addQueryValueHandler('FontSize', () => fontSizeQuery(editor));
  27672. editor.editorCommands.addQueryValueHandler('LineHeight', () => lineHeightQuery(editor));
  27673. };
  27674. const registerCommands$7 = editor => {
  27675. registerExecCommands$2(editor);
  27676. registerQueryValueCommands(editor);
  27677. };
  27678. const registerCommands$6 = editor => {
  27679. editor.editorCommands.addCommands({
  27680. mceAddUndoLevel: () => {
  27681. editor.undoManager.add();
  27682. },
  27683. mceEndUndoLevel: () => {
  27684. editor.undoManager.add();
  27685. },
  27686. Undo: () => {
  27687. editor.undoManager.undo();
  27688. },
  27689. Redo: () => {
  27690. editor.undoManager.redo();
  27691. }
  27692. });
  27693. };
  27694. const registerCommands$5 = editor => {
  27695. editor.editorCommands.addCommands({
  27696. Indent: () => {
  27697. indent(editor);
  27698. },
  27699. Outdent: () => {
  27700. outdent(editor);
  27701. }
  27702. });
  27703. editor.editorCommands.addCommands({ Outdent: () => canOutdent(editor) }, 'state');
  27704. };
  27705. const registerCommands$4 = editor => {
  27706. const applyLinkToSelection = (_command, _ui, value) => {
  27707. const linkDetails = isString(value) ? { href: value } : value;
  27708. const anchor = editor.dom.getParent(editor.selection.getNode(), 'a');
  27709. if (isObject(linkDetails) && isString(linkDetails.href)) {
  27710. linkDetails.href = linkDetails.href.replace(/ /g, '%20');
  27711. if (!anchor || !linkDetails.href) {
  27712. editor.formatter.remove('link');
  27713. }
  27714. if (linkDetails.href) {
  27715. editor.formatter.apply('link', linkDetails, anchor);
  27716. }
  27717. }
  27718. };
  27719. editor.editorCommands.addCommands({
  27720. unlink: () => {
  27721. if (editor.selection.isCollapsed()) {
  27722. const elm = editor.dom.getParent(editor.selection.getStart(), 'a');
  27723. if (elm) {
  27724. editor.dom.remove(elm, true);
  27725. }
  27726. return;
  27727. }
  27728. editor.formatter.remove('link');
  27729. },
  27730. mceInsertLink: applyLinkToSelection,
  27731. createLink: applyLinkToSelection
  27732. });
  27733. };
  27734. const registerExecCommands$1 = editor => {
  27735. editor.editorCommands.addCommands({
  27736. 'InsertUnorderedList,InsertOrderedList': command => {
  27737. editor.getDoc().execCommand(command);
  27738. const listElm = editor.dom.getParent(editor.selection.getNode(), 'ol,ul');
  27739. if (listElm) {
  27740. const listParent = listElm.parentNode;
  27741. if (listParent && /^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
  27742. const bm = editor.selection.getBookmark();
  27743. editor.dom.split(listParent, listElm);
  27744. editor.selection.moveToBookmark(bm);
  27745. }
  27746. }
  27747. }
  27748. });
  27749. };
  27750. const registerQueryStateCommands = editor => {
  27751. editor.editorCommands.addCommands({
  27752. 'InsertUnorderedList,InsertOrderedList': command => {
  27753. const list = editor.dom.getParent(editor.selection.getNode(), 'ul,ol');
  27754. return list && (command === 'insertunorderedlist' && list.tagName === 'UL' || command === 'insertorderedlist' && list.tagName === 'OL');
  27755. }
  27756. }, 'state');
  27757. };
  27758. const registerCommands$3 = editor => {
  27759. registerExecCommands$1(editor);
  27760. registerQueryStateCommands(editor);
  27761. };
  27762. const registerCommands$2 = editor => {
  27763. editor.editorCommands.addCommands({
  27764. insertParagraph: () => {
  27765. insertBreak(blockbreak, editor);
  27766. },
  27767. mceInsertNewLine: (_command, _ui, value) => {
  27768. insert(editor, value);
  27769. },
  27770. InsertLineBreak: (_command, _ui, _value) => {
  27771. insertBreak(linebreak, editor);
  27772. }
  27773. });
  27774. };
  27775. const registerCommands$1 = editor => {
  27776. editor.editorCommands.addCommands({
  27777. mceSelectNodeDepth: (_command, _ui, value) => {
  27778. let counter = 0;
  27779. editor.dom.getParent(editor.selection.getNode(), node => {
  27780. if (isElement$6(node) && counter++ === value) {
  27781. editor.selection.select(node);
  27782. return false;
  27783. } else {
  27784. return true;
  27785. }
  27786. }, editor.getBody());
  27787. },
  27788. mceSelectNode: (_command, _ui, value) => {
  27789. editor.selection.select(value);
  27790. },
  27791. selectAll: () => {
  27792. const editingHost = editor.dom.getParent(editor.selection.getStart(), isContentEditableTrue$3);
  27793. if (editingHost) {
  27794. const rng = editor.dom.createRng();
  27795. rng.selectNodeContents(editingHost);
  27796. editor.selection.setRng(rng);
  27797. }
  27798. }
  27799. });
  27800. };
  27801. const registerExecCommands = editor => {
  27802. editor.editorCommands.addCommands({
  27803. mceRemoveNode: (_command, _ui, value) => {
  27804. const node = value !== null && value !== void 0 ? value : editor.selection.getNode();
  27805. if (node !== editor.getBody()) {
  27806. const bm = editor.selection.getBookmark();
  27807. editor.dom.remove(node, true);
  27808. editor.selection.moveToBookmark(bm);
  27809. }
  27810. },
  27811. mcePrint: () => {
  27812. editor.getWin().print();
  27813. },
  27814. mceFocus: (_command, _ui, value) => {
  27815. focus(editor, value === true);
  27816. },
  27817. mceToggleVisualAid: () => {
  27818. editor.hasVisual = !editor.hasVisual;
  27819. editor.addVisual();
  27820. }
  27821. });
  27822. };
  27823. const registerCommands = editor => {
  27824. registerCommands$a(editor);
  27825. registerCommands$9(editor);
  27826. registerCommands$6(editor);
  27827. registerCommands$1(editor);
  27828. registerCommands$8(editor);
  27829. registerCommands$4(editor);
  27830. registerCommands$5(editor);
  27831. registerCommands$2(editor);
  27832. registerCommands$3(editor);
  27833. registerCommands$7(editor);
  27834. registerExecCommands(editor);
  27835. };
  27836. const selectionSafeCommands = ['toggleview'];
  27837. const isSelectionSafeCommand = command => contains$2(selectionSafeCommands, command.toLowerCase());
  27838. class EditorCommands {
  27839. constructor(editor) {
  27840. this.commands = {
  27841. state: {},
  27842. exec: {},
  27843. value: {}
  27844. };
  27845. this.editor = editor;
  27846. }
  27847. execCommand(command, ui = false, value, args) {
  27848. const editor = this.editor;
  27849. const lowerCaseCommand = command.toLowerCase();
  27850. const skipFocus = args === null || args === void 0 ? void 0 : args.skip_focus;
  27851. if (editor.removed) {
  27852. return false;
  27853. }
  27854. if (lowerCaseCommand !== 'mcefocus') {
  27855. if (!/^(mceAddUndoLevel|mceEndUndoLevel)$/i.test(lowerCaseCommand) && !skipFocus) {
  27856. editor.focus();
  27857. } else {
  27858. restore(editor);
  27859. }
  27860. }
  27861. const eventArgs = editor.dispatch('BeforeExecCommand', {
  27862. command,
  27863. ui,
  27864. value
  27865. });
  27866. if (eventArgs.isDefaultPrevented()) {
  27867. return false;
  27868. }
  27869. const func = this.commands.exec[lowerCaseCommand];
  27870. if (isFunction(func)) {
  27871. func(lowerCaseCommand, ui, value);
  27872. editor.dispatch('ExecCommand', {
  27873. command,
  27874. ui,
  27875. value
  27876. });
  27877. return true;
  27878. }
  27879. return false;
  27880. }
  27881. queryCommandState(command) {
  27882. if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
  27883. return false;
  27884. }
  27885. const lowerCaseCommand = command.toLowerCase();
  27886. const func = this.commands.state[lowerCaseCommand];
  27887. if (isFunction(func)) {
  27888. return func(lowerCaseCommand);
  27889. }
  27890. return false;
  27891. }
  27892. queryCommandValue(command) {
  27893. if (!isSelectionSafeCommand(command) && this.editor.quirks.isHidden() || this.editor.removed) {
  27894. return '';
  27895. }
  27896. const lowerCaseCommand = command.toLowerCase();
  27897. const func = this.commands.value[lowerCaseCommand];
  27898. if (isFunction(func)) {
  27899. return func(lowerCaseCommand);
  27900. }
  27901. return '';
  27902. }
  27903. addCommands(commandList, type = 'exec') {
  27904. const commands = this.commands;
  27905. each$d(commandList, (callback, command) => {
  27906. each$e(command.toLowerCase().split(','), command => {
  27907. commands[type][command] = callback;
  27908. });
  27909. });
  27910. }
  27911. addCommand(command, callback, scope) {
  27912. const lowerCaseCommand = command.toLowerCase();
  27913. this.commands.exec[lowerCaseCommand] = (_command, ui, value) => callback.call(scope !== null && scope !== void 0 ? scope : this.editor, ui, value);
  27914. }
  27915. queryCommandSupported(command) {
  27916. const lowerCaseCommand = command.toLowerCase();
  27917. if (this.commands.exec[lowerCaseCommand]) {
  27918. return true;
  27919. } else {
  27920. return false;
  27921. }
  27922. }
  27923. addQueryStateHandler(command, callback, scope) {
  27924. this.commands.state[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
  27925. }
  27926. addQueryValueHandler(command, callback, scope) {
  27927. this.commands.value[command.toLowerCase()] = () => callback.call(scope !== null && scope !== void 0 ? scope : this.editor);
  27928. }
  27929. }
  27930. const internalContentEditableAttr = 'data-mce-contenteditable';
  27931. const toggleClass = (elm, cls, state) => {
  27932. if (has(elm, cls) && !state) {
  27933. remove$8(elm, cls);
  27934. } else if (state) {
  27935. add$2(elm, cls);
  27936. }
  27937. };
  27938. const setEditorCommandState = (editor, cmd, state) => {
  27939. try {
  27940. editor.getDoc().execCommand(cmd, false, String(state));
  27941. } catch (ex) {
  27942. }
  27943. };
  27944. const setContentEditable = (elm, state) => {
  27945. elm.dom.contentEditable = state ? 'true' : 'false';
  27946. };
  27947. const switchOffContentEditableTrue = elm => {
  27948. each$e(descendants(elm, '*[contenteditable="true"]'), elm => {
  27949. set$2(elm, internalContentEditableAttr, 'true');
  27950. setContentEditable(elm, false);
  27951. });
  27952. };
  27953. const switchOnContentEditableTrue = elm => {
  27954. each$e(descendants(elm, `*[${ internalContentEditableAttr }="true"]`), elm => {
  27955. remove$b(elm, internalContentEditableAttr);
  27956. setContentEditable(elm, true);
  27957. });
  27958. };
  27959. const removeFakeSelection = editor => {
  27960. Optional.from(editor.selection.getNode()).each(elm => {
  27961. elm.removeAttribute('data-mce-selected');
  27962. });
  27963. };
  27964. const restoreFakeSelection = editor => {
  27965. editor.selection.setRng(editor.selection.getRng());
  27966. };
  27967. const toggleReadOnly = (editor, state) => {
  27968. const body = SugarElement.fromDom(editor.getBody());
  27969. toggleClass(body, 'mce-content-readonly', state);
  27970. if (state) {
  27971. editor.selection.controlSelection.hideResizeRect();
  27972. editor._selectionOverrides.hideFakeCaret();
  27973. removeFakeSelection(editor);
  27974. editor.readonly = true;
  27975. setContentEditable(body, false);
  27976. switchOffContentEditableTrue(body);
  27977. } else {
  27978. editor.readonly = false;
  27979. setContentEditable(body, true);
  27980. switchOnContentEditableTrue(body);
  27981. setEditorCommandState(editor, 'StyleWithCSS', false);
  27982. setEditorCommandState(editor, 'enableInlineTableEditing', false);
  27983. setEditorCommandState(editor, 'enableObjectResizing', false);
  27984. if (hasEditorOrUiFocus(editor)) {
  27985. editor.focus();
  27986. }
  27987. restoreFakeSelection(editor);
  27988. editor.nodeChanged();
  27989. }
  27990. };
  27991. const isReadOnly = editor => editor.readonly;
  27992. const registerFilters = editor => {
  27993. editor.parser.addAttributeFilter('contenteditable', nodes => {
  27994. if (isReadOnly(editor)) {
  27995. each$e(nodes, node => {
  27996. node.attr(internalContentEditableAttr, node.attr('contenteditable'));
  27997. node.attr('contenteditable', 'false');
  27998. });
  27999. }
  28000. });
  28001. editor.serializer.addAttributeFilter(internalContentEditableAttr, nodes => {
  28002. if (isReadOnly(editor)) {
  28003. each$e(nodes, node => {
  28004. node.attr('contenteditable', node.attr(internalContentEditableAttr));
  28005. });
  28006. }
  28007. });
  28008. editor.serializer.addTempAttr(internalContentEditableAttr);
  28009. };
  28010. const registerReadOnlyContentFilters = editor => {
  28011. if (editor.serializer) {
  28012. registerFilters(editor);
  28013. } else {
  28014. editor.on('PreInit', () => {
  28015. registerFilters(editor);
  28016. });
  28017. }
  28018. };
  28019. const isClickEvent = e => e.type === 'click';
  28020. const allowedEvents = ['copy'];
  28021. const isReadOnlyAllowedEvent = e => contains$2(allowedEvents, e.type);
  28022. const getAnchorHrefOpt = (editor, elm) => {
  28023. const isRoot = elm => eq(elm, SugarElement.fromDom(editor.getBody()));
  28024. return closest$3(elm, 'a', isRoot).bind(a => getOpt(a, 'href'));
  28025. };
  28026. const processReadonlyEvents = (editor, e) => {
  28027. if (isClickEvent(e) && !VK.metaKeyPressed(e)) {
  28028. const elm = SugarElement.fromDom(e.target);
  28029. getAnchorHrefOpt(editor, elm).each(href => {
  28030. e.preventDefault();
  28031. if (/^#/.test(href)) {
  28032. const targetEl = editor.dom.select(`${ href },[name="${ removeLeading(href, '#') }"]`);
  28033. if (targetEl.length) {
  28034. editor.selection.scrollIntoView(targetEl[0], true);
  28035. }
  28036. } else {
  28037. window.open(href, '_blank', 'rel=noopener noreferrer,menubar=yes,toolbar=yes,location=yes,status=yes,resizable=yes,scrollbars=yes');
  28038. }
  28039. });
  28040. } else if (isReadOnlyAllowedEvent(e)) {
  28041. editor.dispatch(e.type, e);
  28042. }
  28043. };
  28044. const registerReadOnlySelectionBlockers = editor => {
  28045. editor.on('ShowCaret', e => {
  28046. if (isReadOnly(editor)) {
  28047. e.preventDefault();
  28048. }
  28049. });
  28050. editor.on('ObjectSelected', e => {
  28051. if (isReadOnly(editor)) {
  28052. e.preventDefault();
  28053. }
  28054. });
  28055. };
  28056. const nativeEvents = Tools.makeMap('focus blur focusin focusout click dblclick mousedown mouseup mousemove mouseover beforepaste paste cut copy selectionchange ' + 'mouseout mouseenter mouseleave wheel keydown keypress keyup input beforeinput contextmenu dragstart dragend dragover ' + 'draggesture dragdrop drop drag submit ' + 'compositionstart compositionend compositionupdate touchstart touchmove touchend touchcancel', ' ');
  28057. class EventDispatcher {
  28058. constructor(settings) {
  28059. this.bindings = {};
  28060. this.settings = settings || {};
  28061. this.scope = this.settings.scope || this;
  28062. this.toggleEvent = this.settings.toggleEvent || never;
  28063. }
  28064. static isNative(name) {
  28065. return !!nativeEvents[name.toLowerCase()];
  28066. }
  28067. fire(name, args) {
  28068. return this.dispatch(name, args);
  28069. }
  28070. dispatch(name, args) {
  28071. const lcName = name.toLowerCase();
  28072. const event = normalize$3(lcName, args !== null && args !== void 0 ? args : {}, this.scope);
  28073. if (this.settings.beforeFire) {
  28074. this.settings.beforeFire(event);
  28075. }
  28076. const handlers = this.bindings[lcName];
  28077. if (handlers) {
  28078. for (let i = 0, l = handlers.length; i < l; i++) {
  28079. const callback = handlers[i];
  28080. if (callback.removed) {
  28081. continue;
  28082. }
  28083. if (callback.once) {
  28084. this.off(lcName, callback.func);
  28085. }
  28086. if (event.isImmediatePropagationStopped()) {
  28087. return event;
  28088. }
  28089. if (callback.func.call(this.scope, event) === false) {
  28090. event.preventDefault();
  28091. return event;
  28092. }
  28093. }
  28094. }
  28095. return event;
  28096. }
  28097. on(name, callback, prepend, extra) {
  28098. if (callback === false) {
  28099. callback = never;
  28100. }
  28101. if (callback) {
  28102. const wrappedCallback = {
  28103. func: callback,
  28104. removed: false
  28105. };
  28106. if (extra) {
  28107. Tools.extend(wrappedCallback, extra);
  28108. }
  28109. const names = name.toLowerCase().split(' ');
  28110. let i = names.length;
  28111. while (i--) {
  28112. const currentName = names[i];
  28113. let handlers = this.bindings[currentName];
  28114. if (!handlers) {
  28115. handlers = [];
  28116. this.toggleEvent(currentName, true);
  28117. }
  28118. if (prepend) {
  28119. handlers = [
  28120. wrappedCallback,
  28121. ...handlers
  28122. ];
  28123. } else {
  28124. handlers = [
  28125. ...handlers,
  28126. wrappedCallback
  28127. ];
  28128. }
  28129. this.bindings[currentName] = handlers;
  28130. }
  28131. }
  28132. return this;
  28133. }
  28134. off(name, callback) {
  28135. if (name) {
  28136. const names = name.toLowerCase().split(' ');
  28137. let i = names.length;
  28138. while (i--) {
  28139. const currentName = names[i];
  28140. let handlers = this.bindings[currentName];
  28141. if (!currentName) {
  28142. each$d(this.bindings, (_value, bindingName) => {
  28143. this.toggleEvent(bindingName, false);
  28144. delete this.bindings[bindingName];
  28145. });
  28146. return this;
  28147. }
  28148. if (handlers) {
  28149. if (!callback) {
  28150. handlers.length = 0;
  28151. } else {
  28152. const filteredHandlers = partition$2(handlers, handler => handler.func === callback);
  28153. handlers = filteredHandlers.fail;
  28154. this.bindings[currentName] = handlers;
  28155. each$e(filteredHandlers.pass, handler => {
  28156. handler.removed = true;
  28157. });
  28158. }
  28159. if (!handlers.length) {
  28160. this.toggleEvent(name, false);
  28161. delete this.bindings[currentName];
  28162. }
  28163. }
  28164. }
  28165. } else {
  28166. each$d(this.bindings, (_value, name) => {
  28167. this.toggleEvent(name, false);
  28168. });
  28169. this.bindings = {};
  28170. }
  28171. return this;
  28172. }
  28173. once(name, callback, prepend) {
  28174. return this.on(name, callback, prepend, { once: true });
  28175. }
  28176. has(name) {
  28177. name = name.toLowerCase();
  28178. const binding = this.bindings[name];
  28179. return !(!binding || binding.length === 0);
  28180. }
  28181. }
  28182. const getEventDispatcher = obj => {
  28183. if (!obj._eventDispatcher) {
  28184. obj._eventDispatcher = new EventDispatcher({
  28185. scope: obj,
  28186. toggleEvent: (name, state) => {
  28187. if (EventDispatcher.isNative(name) && obj.toggleNativeEvent) {
  28188. obj.toggleNativeEvent(name, state);
  28189. }
  28190. }
  28191. });
  28192. }
  28193. return obj._eventDispatcher;
  28194. };
  28195. const Observable = {
  28196. fire(name, args, bubble) {
  28197. return this.dispatch(name, args, bubble);
  28198. },
  28199. dispatch(name, args, bubble) {
  28200. const self = this;
  28201. if (self.removed && name !== 'remove' && name !== 'detach') {
  28202. return normalize$3(name.toLowerCase(), args !== null && args !== void 0 ? args : {}, self);
  28203. }
  28204. const dispatcherArgs = getEventDispatcher(self).dispatch(name, args);
  28205. if (bubble !== false && self.parent) {
  28206. let parent = self.parent();
  28207. while (parent && !dispatcherArgs.isPropagationStopped()) {
  28208. parent.dispatch(name, dispatcherArgs, false);
  28209. parent = parent.parent ? parent.parent() : undefined;
  28210. }
  28211. }
  28212. return dispatcherArgs;
  28213. },
  28214. on(name, callback, prepend) {
  28215. return getEventDispatcher(this).on(name, callback, prepend);
  28216. },
  28217. off(name, callback) {
  28218. return getEventDispatcher(this).off(name, callback);
  28219. },
  28220. once(name, callback) {
  28221. return getEventDispatcher(this).once(name, callback);
  28222. },
  28223. hasEventListeners(name) {
  28224. return getEventDispatcher(this).has(name);
  28225. }
  28226. };
  28227. const DOM$2 = DOMUtils.DOM;
  28228. let customEventRootDelegates;
  28229. const getEventTarget = (editor, eventName) => {
  28230. if (eventName === 'selectionchange') {
  28231. return editor.getDoc();
  28232. }
  28233. if (!editor.inline && /^mouse|touch|click|contextmenu|drop|dragover|dragend/.test(eventName)) {
  28234. return editor.getDoc().documentElement;
  28235. }
  28236. const eventRoot = getEventRoot(editor);
  28237. if (eventRoot) {
  28238. if (!editor.eventRoot) {
  28239. editor.eventRoot = DOM$2.select(eventRoot)[0];
  28240. }
  28241. return editor.eventRoot;
  28242. }
  28243. return editor.getBody();
  28244. };
  28245. const isListening = editor => !editor.hidden && !isReadOnly(editor);
  28246. const fireEvent = (editor, eventName, e) => {
  28247. if (isListening(editor)) {
  28248. editor.dispatch(eventName, e);
  28249. } else if (isReadOnly(editor)) {
  28250. processReadonlyEvents(editor, e);
  28251. }
  28252. };
  28253. const bindEventDelegate = (editor, eventName) => {
  28254. if (!editor.delegates) {
  28255. editor.delegates = {};
  28256. }
  28257. if (editor.delegates[eventName] || editor.removed) {
  28258. return;
  28259. }
  28260. const eventRootElm = getEventTarget(editor, eventName);
  28261. if (getEventRoot(editor)) {
  28262. if (!customEventRootDelegates) {
  28263. customEventRootDelegates = {};
  28264. editor.editorManager.on('removeEditor', () => {
  28265. if (!editor.editorManager.activeEditor) {
  28266. if (customEventRootDelegates) {
  28267. each$d(customEventRootDelegates, (_value, name) => {
  28268. editor.dom.unbind(getEventTarget(editor, name));
  28269. });
  28270. customEventRootDelegates = null;
  28271. }
  28272. }
  28273. });
  28274. }
  28275. if (customEventRootDelegates[eventName]) {
  28276. return;
  28277. }
  28278. const delegate = e => {
  28279. const target = e.target;
  28280. const editors = editor.editorManager.get();
  28281. let i = editors.length;
  28282. while (i--) {
  28283. const body = editors[i].getBody();
  28284. if (body === target || DOM$2.isChildOf(target, body)) {
  28285. fireEvent(editors[i], eventName, e);
  28286. }
  28287. }
  28288. };
  28289. customEventRootDelegates[eventName] = delegate;
  28290. DOM$2.bind(eventRootElm, eventName, delegate);
  28291. } else {
  28292. const delegate = e => {
  28293. fireEvent(editor, eventName, e);
  28294. };
  28295. DOM$2.bind(eventRootElm, eventName, delegate);
  28296. editor.delegates[eventName] = delegate;
  28297. }
  28298. };
  28299. const EditorObservable = {
  28300. ...Observable,
  28301. bindPendingEventDelegates() {
  28302. const self = this;
  28303. Tools.each(self._pendingNativeEvents, name => {
  28304. bindEventDelegate(self, name);
  28305. });
  28306. },
  28307. toggleNativeEvent(name, state) {
  28308. const self = this;
  28309. if (name === 'focus' || name === 'blur') {
  28310. return;
  28311. }
  28312. if (self.removed) {
  28313. return;
  28314. }
  28315. if (state) {
  28316. if (self.initialized) {
  28317. bindEventDelegate(self, name);
  28318. } else {
  28319. if (!self._pendingNativeEvents) {
  28320. self._pendingNativeEvents = [name];
  28321. } else {
  28322. self._pendingNativeEvents.push(name);
  28323. }
  28324. }
  28325. } else if (self.initialized && self.delegates) {
  28326. self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]);
  28327. delete self.delegates[name];
  28328. }
  28329. },
  28330. unbindAllNativeEvents() {
  28331. const self = this;
  28332. const body = self.getBody();
  28333. const dom = self.dom;
  28334. if (self.delegates) {
  28335. each$d(self.delegates, (value, name) => {
  28336. self.dom.unbind(getEventTarget(self, name), name, value);
  28337. });
  28338. delete self.delegates;
  28339. }
  28340. if (!self.inline && body && dom) {
  28341. body.onload = null;
  28342. dom.unbind(self.getWin());
  28343. dom.unbind(self.getDoc());
  28344. }
  28345. if (dom) {
  28346. dom.unbind(body);
  28347. dom.unbind(self.getContainer());
  28348. }
  28349. }
  28350. };
  28351. const stringListProcessor = value => {
  28352. if (isString(value)) {
  28353. return {
  28354. value: value.split(/[ ,]/),
  28355. valid: true
  28356. };
  28357. } else if (isArrayOf(value, isString)) {
  28358. return {
  28359. value,
  28360. valid: true
  28361. };
  28362. } else {
  28363. return {
  28364. valid: false,
  28365. message: `The value must be a string[] or a comma/space separated string.`
  28366. };
  28367. }
  28368. };
  28369. const getBuiltInProcessor = type => {
  28370. const validator = (() => {
  28371. switch (type) {
  28372. case 'array':
  28373. return isArray$1;
  28374. case 'boolean':
  28375. return isBoolean;
  28376. case 'function':
  28377. return isFunction;
  28378. case 'number':
  28379. return isNumber;
  28380. case 'object':
  28381. return isObject;
  28382. case 'string':
  28383. return isString;
  28384. case 'string[]':
  28385. return stringListProcessor;
  28386. case 'object[]':
  28387. return val => isArrayOf(val, isObject);
  28388. case 'regexp':
  28389. return val => is$4(val, RegExp);
  28390. default:
  28391. return always;
  28392. }
  28393. })();
  28394. return value => processValue(value, validator, `The value must be a ${ type }.`);
  28395. };
  28396. const isBuiltInSpec = spec => isString(spec.processor);
  28397. const getErrorMessage = (message, result) => {
  28398. const additionalText = isEmpty$3(result.message) ? '' : `. ${ result.message }`;
  28399. return message + additionalText;
  28400. };
  28401. const isValidResult = result => result.valid;
  28402. const processValue = (value, processor, message = '') => {
  28403. const result = processor(value);
  28404. if (isBoolean(result)) {
  28405. return result ? {
  28406. value: value,
  28407. valid: true
  28408. } : {
  28409. valid: false,
  28410. message
  28411. };
  28412. } else {
  28413. return result;
  28414. }
  28415. };
  28416. const processDefaultValue = (name, defaultValue, processor) => {
  28417. if (!isUndefined(defaultValue)) {
  28418. const result = processValue(defaultValue, processor);
  28419. if (isValidResult(result)) {
  28420. return result.value;
  28421. } else {
  28422. console.error(getErrorMessage(`Invalid default value passed for the "${ name }" option`, result));
  28423. }
  28424. }
  28425. return undefined;
  28426. };
  28427. const create$5 = (editor, initialOptions) => {
  28428. const registry = {};
  28429. const values = {};
  28430. const setValue = (name, value, processor) => {
  28431. const result = processValue(value, processor);
  28432. if (isValidResult(result)) {
  28433. values[name] = result.value;
  28434. return true;
  28435. } else {
  28436. console.warn(getErrorMessage(`Invalid value passed for the ${ name } option`, result));
  28437. return false;
  28438. }
  28439. };
  28440. const register = (name, spec) => {
  28441. const processor = isBuiltInSpec(spec) ? getBuiltInProcessor(spec.processor) : spec.processor;
  28442. const defaultValue = processDefaultValue(name, spec.default, processor);
  28443. registry[name] = {
  28444. ...spec,
  28445. default: defaultValue,
  28446. processor
  28447. };
  28448. const initValue = get$a(values, name).orThunk(() => get$a(initialOptions, name));
  28449. initValue.each(value => setValue(name, value, processor));
  28450. };
  28451. const isRegistered = name => has$2(registry, name);
  28452. const get = name => get$a(values, name).orThunk(() => get$a(registry, name).map(spec => spec.default)).getOrUndefined();
  28453. const set = (name, value) => {
  28454. if (!isRegistered(name)) {
  28455. console.warn(`"${ name }" is not a registered option. Ensure the option has been registered before setting a value.`);
  28456. return false;
  28457. } else {
  28458. const spec = registry[name];
  28459. if (spec.immutable) {
  28460. console.error(`"${ name }" is an immutable option and cannot be updated`);
  28461. return false;
  28462. } else {
  28463. return setValue(name, value, spec.processor);
  28464. }
  28465. }
  28466. };
  28467. const unset = name => {
  28468. const registered = isRegistered(name);
  28469. if (registered) {
  28470. delete values[name];
  28471. }
  28472. return registered;
  28473. };
  28474. const isSet = name => has$2(values, name);
  28475. return {
  28476. register,
  28477. isRegistered,
  28478. get,
  28479. set,
  28480. unset,
  28481. isSet
  28482. };
  28483. };
  28484. const defaultModes = [
  28485. 'design',
  28486. 'readonly'
  28487. ];
  28488. const switchToMode = (editor, activeMode, availableModes, mode) => {
  28489. const oldMode = availableModes[activeMode.get()];
  28490. const newMode = availableModes[mode];
  28491. try {
  28492. newMode.activate();
  28493. } catch (e) {
  28494. console.error(`problem while activating editor mode ${ mode }:`, e);
  28495. return;
  28496. }
  28497. oldMode.deactivate();
  28498. if (oldMode.editorReadOnly !== newMode.editorReadOnly) {
  28499. toggleReadOnly(editor, newMode.editorReadOnly);
  28500. }
  28501. activeMode.set(mode);
  28502. fireSwitchMode(editor, mode);
  28503. };
  28504. const setMode = (editor, availableModes, activeMode, mode) => {
  28505. if (mode === activeMode.get()) {
  28506. return;
  28507. } else if (!has$2(availableModes, mode)) {
  28508. throw new Error(`Editor mode '${ mode }' is invalid`);
  28509. }
  28510. if (editor.initialized) {
  28511. switchToMode(editor, activeMode, availableModes, mode);
  28512. } else {
  28513. editor.on('init', () => switchToMode(editor, activeMode, availableModes, mode));
  28514. }
  28515. };
  28516. const registerMode = (availableModes, mode, api) => {
  28517. if (contains$2(defaultModes, mode)) {
  28518. throw new Error(`Cannot override default mode ${ mode }`);
  28519. }
  28520. return {
  28521. ...availableModes,
  28522. [mode]: {
  28523. ...api,
  28524. deactivate: () => {
  28525. try {
  28526. api.deactivate();
  28527. } catch (e) {
  28528. console.error(`problem while deactivating editor mode ${ mode }:`, e);
  28529. }
  28530. }
  28531. }
  28532. };
  28533. };
  28534. const create$4 = editor => {
  28535. const activeMode = Cell('design');
  28536. const availableModes = Cell({
  28537. design: {
  28538. activate: noop,
  28539. deactivate: noop,
  28540. editorReadOnly: false
  28541. },
  28542. readonly: {
  28543. activate: noop,
  28544. deactivate: noop,
  28545. editorReadOnly: true
  28546. }
  28547. });
  28548. registerReadOnlyContentFilters(editor);
  28549. registerReadOnlySelectionBlockers(editor);
  28550. return {
  28551. isReadOnly: () => isReadOnly(editor),
  28552. set: mode => setMode(editor, availableModes.get(), activeMode, mode),
  28553. get: () => activeMode.get(),
  28554. register: (mode, api) => {
  28555. availableModes.set(registerMode(availableModes.get(), mode, api));
  28556. }
  28557. };
  28558. };
  28559. const each$2 = Tools.each, explode = Tools.explode;
  28560. const keyCodeLookup = {
  28561. f1: 112,
  28562. f2: 113,
  28563. f3: 114,
  28564. f4: 115,
  28565. f5: 116,
  28566. f6: 117,
  28567. f7: 118,
  28568. f8: 119,
  28569. f9: 120,
  28570. f10: 121,
  28571. f11: 122,
  28572. f12: 123
  28573. };
  28574. const modifierNames = Tools.makeMap('alt,ctrl,shift,meta,access');
  28575. const isModifier = key => key in modifierNames;
  28576. const parseShortcut = pattern => {
  28577. const shortcut = {};
  28578. const isMac = Env.os.isMacOS() || Env.os.isiOS();
  28579. each$2(explode(pattern.toLowerCase(), '+'), value => {
  28580. if (isModifier(value)) {
  28581. shortcut[value] = true;
  28582. } else {
  28583. if (/^[0-9]{2,}$/.test(value)) {
  28584. shortcut.keyCode = parseInt(value, 10);
  28585. } else {
  28586. shortcut.charCode = value.charCodeAt(0);
  28587. shortcut.keyCode = keyCodeLookup[value] || value.toUpperCase().charCodeAt(0);
  28588. }
  28589. }
  28590. });
  28591. const id = [shortcut.keyCode];
  28592. let key;
  28593. for (key in modifierNames) {
  28594. if (shortcut[key]) {
  28595. id.push(key);
  28596. } else {
  28597. shortcut[key] = false;
  28598. }
  28599. }
  28600. shortcut.id = id.join(',');
  28601. if (shortcut.access) {
  28602. shortcut.alt = true;
  28603. if (isMac) {
  28604. shortcut.ctrl = true;
  28605. } else {
  28606. shortcut.shift = true;
  28607. }
  28608. }
  28609. if (shortcut.meta) {
  28610. if (isMac) {
  28611. shortcut.meta = true;
  28612. } else {
  28613. shortcut.ctrl = true;
  28614. shortcut.meta = false;
  28615. }
  28616. }
  28617. return shortcut;
  28618. };
  28619. class Shortcuts {
  28620. constructor(editor) {
  28621. this.shortcuts = {};
  28622. this.pendingPatterns = [];
  28623. this.editor = editor;
  28624. const self = this;
  28625. editor.on('keyup keypress keydown', e => {
  28626. if ((self.hasModifier(e) || self.isFunctionKey(e)) && !e.isDefaultPrevented()) {
  28627. each$2(self.shortcuts, shortcut => {
  28628. if (self.matchShortcut(e, shortcut)) {
  28629. self.pendingPatterns = shortcut.subpatterns.slice(0);
  28630. if (e.type === 'keydown') {
  28631. self.executeShortcutAction(shortcut);
  28632. }
  28633. }
  28634. });
  28635. if (self.matchShortcut(e, self.pendingPatterns[0])) {
  28636. if (self.pendingPatterns.length === 1) {
  28637. if (e.type === 'keydown') {
  28638. self.executeShortcutAction(self.pendingPatterns[0]);
  28639. }
  28640. }
  28641. self.pendingPatterns.shift();
  28642. }
  28643. }
  28644. });
  28645. }
  28646. add(pattern, desc, cmdFunc, scope) {
  28647. const self = this;
  28648. const func = self.normalizeCommandFunc(cmdFunc);
  28649. each$2(explode(Tools.trim(pattern)), pattern => {
  28650. const shortcut = self.createShortcut(pattern, desc, func, scope);
  28651. self.shortcuts[shortcut.id] = shortcut;
  28652. });
  28653. return true;
  28654. }
  28655. remove(pattern) {
  28656. const shortcut = this.createShortcut(pattern);
  28657. if (this.shortcuts[shortcut.id]) {
  28658. delete this.shortcuts[shortcut.id];
  28659. return true;
  28660. }
  28661. return false;
  28662. }
  28663. normalizeCommandFunc(cmdFunc) {
  28664. const self = this;
  28665. const cmd = cmdFunc;
  28666. if (typeof cmd === 'string') {
  28667. return () => {
  28668. self.editor.execCommand(cmd, false, null);
  28669. };
  28670. } else if (Tools.isArray(cmd)) {
  28671. return () => {
  28672. self.editor.execCommand(cmd[0], cmd[1], cmd[2]);
  28673. };
  28674. } else {
  28675. return cmd;
  28676. }
  28677. }
  28678. createShortcut(pattern, desc, cmdFunc, scope) {
  28679. const shortcuts = Tools.map(explode(pattern, '>'), parseShortcut);
  28680. shortcuts[shortcuts.length - 1] = Tools.extend(shortcuts[shortcuts.length - 1], {
  28681. func: cmdFunc,
  28682. scope: scope || this.editor
  28683. });
  28684. return Tools.extend(shortcuts[0], {
  28685. desc: this.editor.translate(desc),
  28686. subpatterns: shortcuts.slice(1)
  28687. });
  28688. }
  28689. hasModifier(e) {
  28690. return e.altKey || e.ctrlKey || e.metaKey;
  28691. }
  28692. isFunctionKey(e) {
  28693. return e.type === 'keydown' && e.keyCode >= 112 && e.keyCode <= 123;
  28694. }
  28695. matchShortcut(e, shortcut) {
  28696. if (!shortcut) {
  28697. return false;
  28698. }
  28699. if (shortcut.ctrl !== e.ctrlKey || shortcut.meta !== e.metaKey) {
  28700. return false;
  28701. }
  28702. if (shortcut.alt !== e.altKey || shortcut.shift !== e.shiftKey) {
  28703. return false;
  28704. }
  28705. if (e.keyCode === shortcut.keyCode || e.charCode && e.charCode === shortcut.charCode) {
  28706. e.preventDefault();
  28707. return true;
  28708. }
  28709. return false;
  28710. }
  28711. executeShortcutAction(shortcut) {
  28712. return shortcut.func ? shortcut.func.call(shortcut.scope) : null;
  28713. }
  28714. }
  28715. const create$3 = () => {
  28716. const buttons = {};
  28717. const menuItems = {};
  28718. const popups = {};
  28719. const icons = {};
  28720. const contextMenus = {};
  28721. const contextToolbars = {};
  28722. const sidebars = {};
  28723. const views = {};
  28724. const add = (collection, type) => (name, spec) => {
  28725. collection[name.toLowerCase()] = {
  28726. ...spec,
  28727. type
  28728. };
  28729. };
  28730. const addIcon = (name, svgData) => icons[name.toLowerCase()] = svgData;
  28731. return {
  28732. addButton: add(buttons, 'button'),
  28733. addGroupToolbarButton: add(buttons, 'grouptoolbarbutton'),
  28734. addToggleButton: add(buttons, 'togglebutton'),
  28735. addMenuButton: add(buttons, 'menubutton'),
  28736. addSplitButton: add(buttons, 'splitbutton'),
  28737. addMenuItem: add(menuItems, 'menuitem'),
  28738. addNestedMenuItem: add(menuItems, 'nestedmenuitem'),
  28739. addToggleMenuItem: add(menuItems, 'togglemenuitem'),
  28740. addAutocompleter: add(popups, 'autocompleter'),
  28741. addContextMenu: add(contextMenus, 'contextmenu'),
  28742. addContextToolbar: add(contextToolbars, 'contexttoolbar'),
  28743. addContextForm: add(contextToolbars, 'contextform'),
  28744. addSidebar: add(sidebars, 'sidebar'),
  28745. addView: add(views, 'views'),
  28746. addIcon,
  28747. getAll: () => ({
  28748. buttons,
  28749. menuItems,
  28750. icons,
  28751. popups,
  28752. contextMenus,
  28753. contextToolbars,
  28754. sidebars,
  28755. views
  28756. })
  28757. };
  28758. };
  28759. const registry = () => {
  28760. const bridge = create$3();
  28761. return {
  28762. addAutocompleter: bridge.addAutocompleter,
  28763. addButton: bridge.addButton,
  28764. addContextForm: bridge.addContextForm,
  28765. addContextMenu: bridge.addContextMenu,
  28766. addContextToolbar: bridge.addContextToolbar,
  28767. addIcon: bridge.addIcon,
  28768. addMenuButton: bridge.addMenuButton,
  28769. addMenuItem: bridge.addMenuItem,
  28770. addNestedMenuItem: bridge.addNestedMenuItem,
  28771. addSidebar: bridge.addSidebar,
  28772. addSplitButton: bridge.addSplitButton,
  28773. addToggleButton: bridge.addToggleButton,
  28774. addGroupToolbarButton: bridge.addGroupToolbarButton,
  28775. addToggleMenuItem: bridge.addToggleMenuItem,
  28776. addView: bridge.addView,
  28777. getAll: bridge.getAll
  28778. };
  28779. };
  28780. const DOM$1 = DOMUtils.DOM;
  28781. const extend = Tools.extend, each$1 = Tools.each;
  28782. class Editor {
  28783. constructor(id, options, editorManager) {
  28784. this.plugins = {};
  28785. this.contentCSS = [];
  28786. this.contentStyles = [];
  28787. this.loadedCSS = {};
  28788. this.isNotDirty = false;
  28789. this.composing = false;
  28790. this.destroyed = false;
  28791. this.hasHiddenInput = false;
  28792. this.iframeElement = null;
  28793. this.initialized = false;
  28794. this.readonly = false;
  28795. this.removed = false;
  28796. this.startContent = '';
  28797. this._pendingNativeEvents = [];
  28798. this._skinLoaded = false;
  28799. this.editorManager = editorManager;
  28800. this.documentBaseUrl = editorManager.documentBaseURL;
  28801. extend(this, EditorObservable);
  28802. const self = this;
  28803. this.id = id;
  28804. this.hidden = false;
  28805. const normalizedOptions = normalizeOptions(editorManager.defaultOptions, options);
  28806. this.options = create$5(self, normalizedOptions);
  28807. register$7(self);
  28808. const getOption = this.options.get;
  28809. if (getOption('deprecation_warnings')) {
  28810. logWarnings(options, normalizedOptions);
  28811. }
  28812. const suffix = getOption('suffix');
  28813. if (suffix) {
  28814. editorManager.suffix = suffix;
  28815. }
  28816. this.suffix = editorManager.suffix;
  28817. const baseUrl = getOption('base_url');
  28818. if (baseUrl) {
  28819. editorManager._setBaseUrl(baseUrl);
  28820. }
  28821. this.baseUri = editorManager.baseURI;
  28822. const referrerPolicy = getReferrerPolicy(self);
  28823. if (referrerPolicy) {
  28824. ScriptLoader.ScriptLoader._setReferrerPolicy(referrerPolicy);
  28825. DOMUtils.DOM.styleSheetLoader._setReferrerPolicy(referrerPolicy);
  28826. }
  28827. const contentCssCors = hasContentCssCors(self);
  28828. if (isNonNullable(contentCssCors)) {
  28829. DOMUtils.DOM.styleSheetLoader._setContentCssCors(contentCssCors);
  28830. }
  28831. AddOnManager.languageLoad = getOption('language_load');
  28832. AddOnManager.baseURL = editorManager.baseURL;
  28833. this.setDirty(false);
  28834. this.documentBaseURI = new URI(getDocumentBaseUrl(self), { base_uri: this.baseUri });
  28835. this.baseURI = this.baseUri;
  28836. this.inline = isInline(self);
  28837. this.hasVisual = isVisualAidsEnabled(self);
  28838. this.shortcuts = new Shortcuts(this);
  28839. this.editorCommands = new EditorCommands(this);
  28840. registerCommands(this);
  28841. const cacheSuffix = getOption('cache_suffix');
  28842. if (cacheSuffix) {
  28843. Env.cacheSuffix = cacheSuffix.replace(/^[\?\&]+/, '');
  28844. }
  28845. this.ui = {
  28846. registry: registry(),
  28847. styleSheetLoader: undefined,
  28848. show: noop,
  28849. hide: noop,
  28850. setEnabled: noop,
  28851. isEnabled: always
  28852. };
  28853. this.mode = create$4(self);
  28854. editorManager.dispatch('SetupEditor', { editor: this });
  28855. const setupCallback = getSetupCallback(self);
  28856. if (isFunction(setupCallback)) {
  28857. setupCallback.call(self, self);
  28858. }
  28859. }
  28860. render() {
  28861. render(this);
  28862. }
  28863. focus(skipFocus) {
  28864. this.execCommand('mceFocus', false, skipFocus);
  28865. }
  28866. hasFocus() {
  28867. return hasFocus(this);
  28868. }
  28869. translate(text) {
  28870. return I18n.translate(text);
  28871. }
  28872. getParam(name, defaultVal, type) {
  28873. const options = this.options;
  28874. if (!options.isRegistered(name)) {
  28875. if (isNonNullable(type)) {
  28876. options.register(name, {
  28877. processor: type,
  28878. default: defaultVal
  28879. });
  28880. } else {
  28881. options.register(name, {
  28882. processor: always,
  28883. default: defaultVal
  28884. });
  28885. }
  28886. }
  28887. return !options.isSet(name) && !isUndefined(defaultVal) ? defaultVal : options.get(name);
  28888. }
  28889. hasPlugin(name, loaded) {
  28890. const hasPlugin = contains$2(getPlugins(this), name);
  28891. if (hasPlugin) {
  28892. return loaded ? PluginManager.get(name) !== undefined : true;
  28893. } else {
  28894. return false;
  28895. }
  28896. }
  28897. nodeChanged(args) {
  28898. this._nodeChangeDispatcher.nodeChanged(args);
  28899. }
  28900. addCommand(name, callback, scope) {
  28901. this.editorCommands.addCommand(name, callback, scope);
  28902. }
  28903. addQueryStateHandler(name, callback, scope) {
  28904. this.editorCommands.addQueryStateHandler(name, callback, scope);
  28905. }
  28906. addQueryValueHandler(name, callback, scope) {
  28907. this.editorCommands.addQueryValueHandler(name, callback, scope);
  28908. }
  28909. addShortcut(pattern, desc, cmdFunc, scope) {
  28910. this.shortcuts.add(pattern, desc, cmdFunc, scope);
  28911. }
  28912. execCommand(cmd, ui, value, args) {
  28913. return this.editorCommands.execCommand(cmd, ui, value, args);
  28914. }
  28915. queryCommandState(cmd) {
  28916. return this.editorCommands.queryCommandState(cmd);
  28917. }
  28918. queryCommandValue(cmd) {
  28919. return this.editorCommands.queryCommandValue(cmd);
  28920. }
  28921. queryCommandSupported(cmd) {
  28922. return this.editorCommands.queryCommandSupported(cmd);
  28923. }
  28924. show() {
  28925. const self = this;
  28926. if (self.hidden) {
  28927. self.hidden = false;
  28928. if (self.inline) {
  28929. self.getBody().contentEditable = 'true';
  28930. } else {
  28931. DOM$1.show(self.getContainer());
  28932. DOM$1.hide(self.id);
  28933. }
  28934. self.load();
  28935. self.dispatch('show');
  28936. }
  28937. }
  28938. hide() {
  28939. const self = this;
  28940. if (!self.hidden) {
  28941. self.save();
  28942. if (self.inline) {
  28943. self.getBody().contentEditable = 'false';
  28944. if (self === self.editorManager.focusedEditor) {
  28945. self.editorManager.focusedEditor = null;
  28946. }
  28947. } else {
  28948. DOM$1.hide(self.getContainer());
  28949. DOM$1.setStyle(self.id, 'display', self.orgDisplay);
  28950. }
  28951. self.hidden = true;
  28952. self.dispatch('hide');
  28953. }
  28954. }
  28955. isHidden() {
  28956. return this.hidden;
  28957. }
  28958. setProgressState(state, time) {
  28959. this.dispatch('ProgressState', {
  28960. state,
  28961. time
  28962. });
  28963. }
  28964. load(args = {}) {
  28965. const self = this;
  28966. const elm = self.getElement();
  28967. if (self.removed) {
  28968. return '';
  28969. }
  28970. if (elm) {
  28971. const loadArgs = {
  28972. ...args,
  28973. load: true
  28974. };
  28975. const value = isTextareaOrInput(elm) ? elm.value : elm.innerHTML;
  28976. const html = self.setContent(value, loadArgs);
  28977. if (!loadArgs.no_events) {
  28978. self.dispatch('LoadContent', {
  28979. ...loadArgs,
  28980. element: elm
  28981. });
  28982. }
  28983. return html;
  28984. } else {
  28985. return '';
  28986. }
  28987. }
  28988. save(args = {}) {
  28989. const self = this;
  28990. let elm = self.getElement();
  28991. if (!elm || !self.initialized || self.removed) {
  28992. return '';
  28993. }
  28994. const getArgs = {
  28995. ...args,
  28996. save: true,
  28997. element: elm
  28998. };
  28999. let html = self.getContent(getArgs);
  29000. const saveArgs = {
  29001. ...getArgs,
  29002. content: html
  29003. };
  29004. if (!saveArgs.no_events) {
  29005. self.dispatch('SaveContent', saveArgs);
  29006. }
  29007. if (saveArgs.format === 'raw') {
  29008. self.dispatch('RawSaveContent', saveArgs);
  29009. }
  29010. html = saveArgs.content;
  29011. if (!isTextareaOrInput(elm)) {
  29012. if (args.is_removing || !self.inline) {
  29013. elm.innerHTML = html;
  29014. }
  29015. const form = DOM$1.getParent(self.id, 'form');
  29016. if (form) {
  29017. each$1(form.elements, elm => {
  29018. if (elm.name === self.id) {
  29019. elm.value = html;
  29020. return false;
  29021. } else {
  29022. return true;
  29023. }
  29024. });
  29025. }
  29026. } else {
  29027. elm.value = html;
  29028. }
  29029. saveArgs.element = getArgs.element = elm = null;
  29030. if (saveArgs.set_dirty !== false) {
  29031. self.setDirty(false);
  29032. }
  29033. return html;
  29034. }
  29035. setContent(content, args) {
  29036. return setContent(this, content, args);
  29037. }
  29038. getContent(args) {
  29039. return getContent(this, args);
  29040. }
  29041. insertContent(content, args) {
  29042. if (args) {
  29043. content = extend({ content }, args);
  29044. }
  29045. this.execCommand('mceInsertContent', false, content);
  29046. }
  29047. resetContent(initialContent) {
  29048. if (initialContent === undefined) {
  29049. setContent(this, this.startContent, { format: 'raw' });
  29050. } else {
  29051. setContent(this, initialContent);
  29052. }
  29053. this.undoManager.reset();
  29054. this.setDirty(false);
  29055. this.nodeChanged();
  29056. }
  29057. isDirty() {
  29058. return !this.isNotDirty;
  29059. }
  29060. setDirty(state) {
  29061. const oldState = !this.isNotDirty;
  29062. this.isNotDirty = !state;
  29063. if (state && state !== oldState) {
  29064. this.dispatch('dirty');
  29065. }
  29066. }
  29067. getContainer() {
  29068. const self = this;
  29069. if (!self.container) {
  29070. self.container = self.editorContainer || DOM$1.get(self.id + '_parent');
  29071. }
  29072. return self.container;
  29073. }
  29074. getContentAreaContainer() {
  29075. return this.contentAreaContainer;
  29076. }
  29077. getElement() {
  29078. if (!this.targetElm) {
  29079. this.targetElm = DOM$1.get(this.id);
  29080. }
  29081. return this.targetElm;
  29082. }
  29083. getWin() {
  29084. const self = this;
  29085. if (!self.contentWindow) {
  29086. const elm = self.iframeElement;
  29087. if (elm) {
  29088. self.contentWindow = elm.contentWindow;
  29089. }
  29090. }
  29091. return self.contentWindow;
  29092. }
  29093. getDoc() {
  29094. const self = this;
  29095. if (!self.contentDocument) {
  29096. const win = self.getWin();
  29097. if (win) {
  29098. self.contentDocument = win.document;
  29099. }
  29100. }
  29101. return self.contentDocument;
  29102. }
  29103. getBody() {
  29104. var _a, _b;
  29105. const doc = this.getDoc();
  29106. return (_b = (_a = this.bodyElement) !== null && _a !== void 0 ? _a : doc === null || doc === void 0 ? void 0 : doc.body) !== null && _b !== void 0 ? _b : null;
  29107. }
  29108. convertURL(url, name, elm) {
  29109. const self = this, getOption = self.options.get;
  29110. const urlConverterCallback = getUrlConverterCallback(self);
  29111. if (isFunction(urlConverterCallback)) {
  29112. return urlConverterCallback.call(self, url, elm, true, name);
  29113. }
  29114. if (!getOption('convert_urls') || elm === 'link' || isObject(elm) && elm.nodeName === 'LINK' || url.indexOf('file:') === 0 || url.length === 0) {
  29115. return url;
  29116. }
  29117. if (getOption('relative_urls')) {
  29118. return self.documentBaseURI.toRelative(url);
  29119. }
  29120. url = self.documentBaseURI.toAbsolute(url, getOption('remove_script_host'));
  29121. return url;
  29122. }
  29123. addVisual(elm) {
  29124. addVisual(this, elm);
  29125. }
  29126. remove() {
  29127. remove$1(this);
  29128. }
  29129. destroy(automatic) {
  29130. destroy(this, automatic);
  29131. }
  29132. uploadImages() {
  29133. return this.editorUpload.uploadImages();
  29134. }
  29135. _scanForImages() {
  29136. return this.editorUpload.scanForImages();
  29137. }
  29138. }
  29139. const DOM = DOMUtils.DOM;
  29140. const each = Tools.each;
  29141. let boundGlobalEvents = false;
  29142. let beforeUnloadDelegate;
  29143. let editors = [];
  29144. const globalEventDelegate = e => {
  29145. const type = e.type;
  29146. each(EditorManager.get(), editor => {
  29147. switch (type) {
  29148. case 'scroll':
  29149. editor.dispatch('ScrollWindow', e);
  29150. break;
  29151. case 'resize':
  29152. editor.dispatch('ResizeWindow', e);
  29153. break;
  29154. }
  29155. });
  29156. };
  29157. const toggleGlobalEvents = state => {
  29158. if (state !== boundGlobalEvents) {
  29159. const DOM = DOMUtils.DOM;
  29160. if (state) {
  29161. DOM.bind(window, 'resize', globalEventDelegate);
  29162. DOM.bind(window, 'scroll', globalEventDelegate);
  29163. } else {
  29164. DOM.unbind(window, 'resize', globalEventDelegate);
  29165. DOM.unbind(window, 'scroll', globalEventDelegate);
  29166. }
  29167. boundGlobalEvents = state;
  29168. }
  29169. };
  29170. const removeEditorFromList = targetEditor => {
  29171. const oldEditors = editors;
  29172. editors = filter$5(editors, editor => {
  29173. return targetEditor !== editor;
  29174. });
  29175. if (EditorManager.activeEditor === targetEditor) {
  29176. EditorManager.activeEditor = editors.length > 0 ? editors[0] : null;
  29177. }
  29178. if (EditorManager.focusedEditor === targetEditor) {
  29179. EditorManager.focusedEditor = null;
  29180. }
  29181. return oldEditors.length !== editors.length;
  29182. };
  29183. const purgeDestroyedEditor = editor => {
  29184. if (editor && editor.initialized && !(editor.getContainer() || editor.getBody()).parentNode) {
  29185. removeEditorFromList(editor);
  29186. editor.unbindAllNativeEvents();
  29187. editor.destroy(true);
  29188. editor.removed = true;
  29189. }
  29190. };
  29191. const isQuirksMode = document.compatMode !== 'CSS1Compat';
  29192. const EditorManager = {
  29193. ...Observable,
  29194. baseURI: null,
  29195. baseURL: null,
  29196. defaultOptions: {},
  29197. documentBaseURL: null,
  29198. suffix: null,
  29199. majorVersion: '6',
  29200. minorVersion: '3.1',
  29201. releaseDate: '2022-12-06',
  29202. i18n: I18n,
  29203. activeEditor: null,
  29204. focusedEditor: null,
  29205. setup() {
  29206. const self = this;
  29207. let baseURL = '';
  29208. let suffix = '';
  29209. let documentBaseURL = URI.getDocumentBaseUrl(document.location);
  29210. if (/^[^:]+:\/\/\/?[^\/]+\//.test(documentBaseURL)) {
  29211. documentBaseURL = documentBaseURL.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
  29212. if (!/[\/\\]$/.test(documentBaseURL)) {
  29213. documentBaseURL += '/';
  29214. }
  29215. }
  29216. const preInit = window.tinymce || window.tinyMCEPreInit;
  29217. if (preInit) {
  29218. baseURL = preInit.base || preInit.baseURL;
  29219. suffix = preInit.suffix;
  29220. } else {
  29221. const scripts = document.getElementsByTagName('script');
  29222. for (let i = 0; i < scripts.length; i++) {
  29223. const src = scripts[i].src || '';
  29224. if (src === '') {
  29225. continue;
  29226. }
  29227. const srcScript = src.substring(src.lastIndexOf('/'));
  29228. if (/tinymce(\.full|\.jquery|)(\.min|\.dev|)\.js/.test(src)) {
  29229. if (srcScript.indexOf('.min') !== -1) {
  29230. suffix = '.min';
  29231. }
  29232. baseURL = src.substring(0, src.lastIndexOf('/'));
  29233. break;
  29234. }
  29235. }
  29236. if (!baseURL && document.currentScript) {
  29237. const src = document.currentScript.src;
  29238. if (src.indexOf('.min') !== -1) {
  29239. suffix = '.min';
  29240. }
  29241. baseURL = src.substring(0, src.lastIndexOf('/'));
  29242. }
  29243. }
  29244. self.baseURL = new URI(documentBaseURL).toAbsolute(baseURL);
  29245. self.documentBaseURL = documentBaseURL;
  29246. self.baseURI = new URI(self.baseURL);
  29247. self.suffix = suffix;
  29248. setup$v(self);
  29249. },
  29250. overrideDefaults(defaultOptions) {
  29251. const baseUrl = defaultOptions.base_url;
  29252. if (baseUrl) {
  29253. this._setBaseUrl(baseUrl);
  29254. }
  29255. const suffix = defaultOptions.suffix;
  29256. if (suffix) {
  29257. this.suffix = suffix;
  29258. }
  29259. this.defaultOptions = defaultOptions;
  29260. const pluginBaseUrls = defaultOptions.plugin_base_urls;
  29261. if (pluginBaseUrls !== undefined) {
  29262. each$d(pluginBaseUrls, (pluginBaseUrl, pluginName) => {
  29263. AddOnManager.PluginManager.urls[pluginName] = pluginBaseUrl;
  29264. });
  29265. }
  29266. },
  29267. init(options) {
  29268. const self = this;
  29269. let result;
  29270. const invalidInlineTargets = Tools.makeMap('area base basefont br col frame hr img input isindex link meta param embed source wbr track ' + 'colgroup option table tbody tfoot thead tr th td script noscript style textarea video audio iframe object menu', ' ');
  29271. const isInvalidInlineTarget = (options, elm) => options.inline && elm.tagName.toLowerCase() in invalidInlineTargets;
  29272. const createId = elm => {
  29273. let id = elm.id;
  29274. if (!id) {
  29275. id = get$a(elm, 'name').filter(name => !DOM.get(name)).getOrThunk(DOM.uniqueId);
  29276. elm.setAttribute('id', id);
  29277. }
  29278. return id;
  29279. };
  29280. const execCallback = name => {
  29281. const callback = options[name];
  29282. if (!callback) {
  29283. return;
  29284. }
  29285. return callback.apply(self, []);
  29286. };
  29287. const findTargets = options => {
  29288. if (Env.browser.isIE() || Env.browser.isEdge()) {
  29289. initError('TinyMCE does not support the browser you are using. For a list of supported' + ' browsers please see: https://www.tiny.cloud/docs/tinymce/6/support/#supportedwebbrowsers');
  29290. return [];
  29291. } else if (isQuirksMode) {
  29292. initError('Failed to initialize the editor as the document is not in standards mode. ' + 'TinyMCE requires standards mode.');
  29293. return [];
  29294. } else if (isString(options.selector)) {
  29295. return DOM.select(options.selector);
  29296. } else if (isNonNullable(options.target)) {
  29297. return [options.target];
  29298. } else {
  29299. return [];
  29300. }
  29301. };
  29302. let provideResults = editors => {
  29303. result = editors;
  29304. };
  29305. const initEditors = () => {
  29306. let initCount = 0;
  29307. const editors = [];
  29308. let targets;
  29309. const createEditor = (id, options, targetElm) => {
  29310. const editor = new Editor(id, options, self);
  29311. editors.push(editor);
  29312. editor.on('init', () => {
  29313. if (++initCount === targets.length) {
  29314. provideResults(editors);
  29315. }
  29316. });
  29317. editor.targetElm = editor.targetElm || targetElm;
  29318. editor.render();
  29319. };
  29320. DOM.unbind(window, 'ready', initEditors);
  29321. execCallback('onpageload');
  29322. targets = unique$1(findTargets(options));
  29323. Tools.each(targets, elm => {
  29324. purgeDestroyedEditor(self.get(elm.id));
  29325. });
  29326. targets = Tools.grep(targets, elm => {
  29327. return !self.get(elm.id);
  29328. });
  29329. if (targets.length === 0) {
  29330. provideResults([]);
  29331. } else {
  29332. each(targets, elm => {
  29333. if (isInvalidInlineTarget(options, elm)) {
  29334. initError('Could not initialize inline editor on invalid inline target element', elm);
  29335. } else {
  29336. createEditor(createId(elm), options, elm);
  29337. }
  29338. });
  29339. }
  29340. };
  29341. DOM.bind(window, 'ready', initEditors);
  29342. return new Promise(resolve => {
  29343. if (result) {
  29344. resolve(result);
  29345. } else {
  29346. provideResults = editors => {
  29347. resolve(editors);
  29348. };
  29349. }
  29350. });
  29351. },
  29352. get(id) {
  29353. if (arguments.length === 0) {
  29354. return editors.slice(0);
  29355. } else if (isString(id)) {
  29356. return find$2(editors, editor => {
  29357. return editor.id === id;
  29358. }).getOr(null);
  29359. } else if (isNumber(id)) {
  29360. return editors[id] ? editors[id] : null;
  29361. } else {
  29362. return null;
  29363. }
  29364. },
  29365. add(editor) {
  29366. const self = this;
  29367. const existingEditor = self.get(editor.id);
  29368. if (existingEditor === editor) {
  29369. return editor;
  29370. }
  29371. if (existingEditor === null) {
  29372. editors.push(editor);
  29373. }
  29374. toggleGlobalEvents(true);
  29375. self.activeEditor = editor;
  29376. self.dispatch('AddEditor', { editor });
  29377. if (!beforeUnloadDelegate) {
  29378. beforeUnloadDelegate = e => {
  29379. const event = self.dispatch('BeforeUnload');
  29380. if (event.returnValue) {
  29381. e.preventDefault();
  29382. e.returnValue = event.returnValue;
  29383. return event.returnValue;
  29384. }
  29385. };
  29386. window.addEventListener('beforeunload', beforeUnloadDelegate);
  29387. }
  29388. return editor;
  29389. },
  29390. createEditor(id, options) {
  29391. return this.add(new Editor(id, options, this));
  29392. },
  29393. remove(selector) {
  29394. const self = this;
  29395. let editor;
  29396. if (!selector) {
  29397. for (let i = editors.length - 1; i >= 0; i--) {
  29398. self.remove(editors[i]);
  29399. }
  29400. return;
  29401. }
  29402. if (isString(selector)) {
  29403. each(DOM.select(selector), elm => {
  29404. editor = self.get(elm.id);
  29405. if (editor) {
  29406. self.remove(editor);
  29407. }
  29408. });
  29409. return;
  29410. }
  29411. editor = selector;
  29412. if (isNull(self.get(editor.id))) {
  29413. return null;
  29414. }
  29415. if (removeEditorFromList(editor)) {
  29416. self.dispatch('RemoveEditor', { editor });
  29417. }
  29418. if (editors.length === 0) {
  29419. window.removeEventListener('beforeunload', beforeUnloadDelegate);
  29420. }
  29421. editor.remove();
  29422. toggleGlobalEvents(editors.length > 0);
  29423. return editor;
  29424. },
  29425. execCommand(cmd, ui, value) {
  29426. var _a;
  29427. const self = this;
  29428. const editorId = isObject(value) ? (_a = value.id) !== null && _a !== void 0 ? _a : value.index : value;
  29429. switch (cmd) {
  29430. case 'mceAddEditor': {
  29431. if (!self.get(editorId)) {
  29432. const editorOptions = value.options;
  29433. new Editor(editorId, editorOptions, self).render();
  29434. }
  29435. return true;
  29436. }
  29437. case 'mceRemoveEditor': {
  29438. const editor = self.get(editorId);
  29439. if (editor) {
  29440. editor.remove();
  29441. }
  29442. return true;
  29443. }
  29444. case 'mceToggleEditor': {
  29445. const editor = self.get(editorId);
  29446. if (!editor) {
  29447. self.execCommand('mceAddEditor', false, value);
  29448. return true;
  29449. }
  29450. if (editor.isHidden()) {
  29451. editor.show();
  29452. } else {
  29453. editor.hide();
  29454. }
  29455. return true;
  29456. }
  29457. }
  29458. if (self.activeEditor) {
  29459. return self.activeEditor.execCommand(cmd, ui, value);
  29460. }
  29461. return false;
  29462. },
  29463. triggerSave: () => {
  29464. each(editors, editor => {
  29465. editor.save();
  29466. });
  29467. },
  29468. addI18n: (code, items) => {
  29469. I18n.add(code, items);
  29470. },
  29471. translate: text => {
  29472. return I18n.translate(text);
  29473. },
  29474. setActive(editor) {
  29475. const activeEditor = this.activeEditor;
  29476. if (this.activeEditor !== editor) {
  29477. if (activeEditor) {
  29478. activeEditor.dispatch('deactivate', { relatedTarget: editor });
  29479. }
  29480. editor.dispatch('activate', { relatedTarget: activeEditor });
  29481. }
  29482. this.activeEditor = editor;
  29483. },
  29484. _setBaseUrl(baseUrl) {
  29485. this.baseURL = new URI(this.documentBaseURL).toAbsolute(baseUrl.replace(/\/+$/, ''));
  29486. this.baseURI = new URI(this.baseURL);
  29487. }
  29488. };
  29489. EditorManager.setup();
  29490. const setup = () => {
  29491. const dataValue = value$2();
  29492. const FakeClipboardItem = items => ({
  29493. items,
  29494. types: keys(items),
  29495. getType: type => get$a(items, type).getOrUndefined()
  29496. });
  29497. const write = data => {
  29498. dataValue.set(data);
  29499. };
  29500. const read = () => dataValue.get().getOrUndefined();
  29501. const clear = dataValue.clear;
  29502. return {
  29503. FakeClipboardItem,
  29504. write,
  29505. read,
  29506. clear
  29507. };
  29508. };
  29509. const FakeClipboard = setup();
  29510. const min = Math.min, max = Math.max, round = Math.round;
  29511. const relativePosition = (rect, targetRect, rel) => {
  29512. let x = targetRect.x;
  29513. let y = targetRect.y;
  29514. const w = rect.w;
  29515. const h = rect.h;
  29516. const targetW = targetRect.w;
  29517. const targetH = targetRect.h;
  29518. const relChars = (rel || '').split('');
  29519. if (relChars[0] === 'b') {
  29520. y += targetH;
  29521. }
  29522. if (relChars[1] === 'r') {
  29523. x += targetW;
  29524. }
  29525. if (relChars[0] === 'c') {
  29526. y += round(targetH / 2);
  29527. }
  29528. if (relChars[1] === 'c') {
  29529. x += round(targetW / 2);
  29530. }
  29531. if (relChars[3] === 'b') {
  29532. y -= h;
  29533. }
  29534. if (relChars[4] === 'r') {
  29535. x -= w;
  29536. }
  29537. if (relChars[3] === 'c') {
  29538. y -= round(h / 2);
  29539. }
  29540. if (relChars[4] === 'c') {
  29541. x -= round(w / 2);
  29542. }
  29543. return create$2(x, y, w, h);
  29544. };
  29545. const findBestRelativePosition = (rect, targetRect, constrainRect, rels) => {
  29546. for (let i = 0; i < rels.length; i++) {
  29547. const pos = relativePosition(rect, targetRect, rels[i]);
  29548. if (pos.x >= constrainRect.x && pos.x + pos.w <= constrainRect.w + constrainRect.x && pos.y >= constrainRect.y && pos.y + pos.h <= constrainRect.h + constrainRect.y) {
  29549. return rels[i];
  29550. }
  29551. }
  29552. return null;
  29553. };
  29554. const inflate = (rect, w, h) => {
  29555. return create$2(rect.x - w, rect.y - h, rect.w + w * 2, rect.h + h * 2);
  29556. };
  29557. const intersect = (rect, cropRect) => {
  29558. const x1 = max(rect.x, cropRect.x);
  29559. const y1 = max(rect.y, cropRect.y);
  29560. const x2 = min(rect.x + rect.w, cropRect.x + cropRect.w);
  29561. const y2 = min(rect.y + rect.h, cropRect.y + cropRect.h);
  29562. if (x2 - x1 < 0 || y2 - y1 < 0) {
  29563. return null;
  29564. }
  29565. return create$2(x1, y1, x2 - x1, y2 - y1);
  29566. };
  29567. const clamp = (rect, clampRect, fixedSize) => {
  29568. let x1 = rect.x;
  29569. let y1 = rect.y;
  29570. let x2 = rect.x + rect.w;
  29571. let y2 = rect.y + rect.h;
  29572. const cx2 = clampRect.x + clampRect.w;
  29573. const cy2 = clampRect.y + clampRect.h;
  29574. const underflowX1 = max(0, clampRect.x - x1);
  29575. const underflowY1 = max(0, clampRect.y - y1);
  29576. const overflowX2 = max(0, x2 - cx2);
  29577. const overflowY2 = max(0, y2 - cy2);
  29578. x1 += underflowX1;
  29579. y1 += underflowY1;
  29580. if (fixedSize) {
  29581. x2 += underflowX1;
  29582. y2 += underflowY1;
  29583. x1 -= overflowX2;
  29584. y1 -= overflowY2;
  29585. }
  29586. x2 -= overflowX2;
  29587. y2 -= overflowY2;
  29588. return create$2(x1, y1, x2 - x1, y2 - y1);
  29589. };
  29590. const create$2 = (x, y, w, h) => {
  29591. return {
  29592. x,
  29593. y,
  29594. w,
  29595. h
  29596. };
  29597. };
  29598. const fromClientRect = clientRect => {
  29599. return create$2(clientRect.left, clientRect.top, clientRect.width, clientRect.height);
  29600. };
  29601. const Rect = {
  29602. inflate,
  29603. relativePosition,
  29604. findBestRelativePosition,
  29605. intersect,
  29606. clamp,
  29607. create: create$2,
  29608. fromClientRect
  29609. };
  29610. const awaiter = (resolveCb, rejectCb, timeout = 1000) => {
  29611. let done = false;
  29612. let timer = null;
  29613. const complete = completer => (...args) => {
  29614. if (!done) {
  29615. done = true;
  29616. if (timer !== null) {
  29617. clearTimeout(timer);
  29618. timer = null;
  29619. }
  29620. completer.apply(null, args);
  29621. }
  29622. };
  29623. const resolve = complete(resolveCb);
  29624. const reject = complete(rejectCb);
  29625. const start = (...args) => {
  29626. if (!done && timer === null) {
  29627. timer = setTimeout(() => reject.apply(null, args), timeout);
  29628. }
  29629. };
  29630. return {
  29631. start,
  29632. resolve,
  29633. reject
  29634. };
  29635. };
  29636. const create$1 = () => {
  29637. const tasks = {};
  29638. const resultFns = {};
  29639. const load = (id, url) => {
  29640. const loadErrMsg = `Script at URL "${ url }" failed to load`;
  29641. const runErrMsg = `Script at URL "${ url }" did not call \`tinymce.Resource.add('${ id }', data)\` within 1 second`;
  29642. if (tasks[id] !== undefined) {
  29643. return tasks[id];
  29644. } else {
  29645. const task = new Promise((resolve, reject) => {
  29646. const waiter = awaiter(resolve, reject);
  29647. resultFns[id] = waiter.resolve;
  29648. ScriptLoader.ScriptLoader.loadScript(url).then(() => waiter.start(runErrMsg), () => waiter.reject(loadErrMsg));
  29649. });
  29650. tasks[id] = task;
  29651. return task;
  29652. }
  29653. };
  29654. const add = (id, data) => {
  29655. if (resultFns[id] !== undefined) {
  29656. resultFns[id](data);
  29657. delete resultFns[id];
  29658. }
  29659. tasks[id] = Promise.resolve(data);
  29660. };
  29661. const unload = id => {
  29662. delete tasks[id];
  29663. };
  29664. return {
  29665. load,
  29666. add,
  29667. unload
  29668. };
  29669. };
  29670. const Resource = create$1();
  29671. const create = () => (() => {
  29672. let data = {};
  29673. let keys = [];
  29674. const storage = {
  29675. getItem: key => {
  29676. const item = data[key];
  29677. return item ? item : null;
  29678. },
  29679. setItem: (key, value) => {
  29680. keys.push(key);
  29681. data[key] = String(value);
  29682. },
  29683. key: index => {
  29684. return keys[index];
  29685. },
  29686. removeItem: key => {
  29687. keys = keys.filter(k => k === key);
  29688. delete data[key];
  29689. },
  29690. clear: () => {
  29691. keys = [];
  29692. data = {};
  29693. },
  29694. length: 0
  29695. };
  29696. Object.defineProperty(storage, 'length', {
  29697. get: () => keys.length,
  29698. configurable: false,
  29699. enumerable: false
  29700. });
  29701. return storage;
  29702. })();
  29703. let localStorage;
  29704. try {
  29705. const test = '__storage_test__';
  29706. localStorage = window.localStorage;
  29707. localStorage.setItem(test, test);
  29708. localStorage.removeItem(test);
  29709. } catch (e) {
  29710. localStorage = create();
  29711. }
  29712. var LocalStorage = localStorage;
  29713. const publicApi = {
  29714. geom: { Rect },
  29715. util: {
  29716. Delay,
  29717. Tools,
  29718. VK,
  29719. URI,
  29720. EventDispatcher,
  29721. Observable,
  29722. I18n,
  29723. LocalStorage,
  29724. ImageUploader
  29725. },
  29726. dom: {
  29727. EventUtils,
  29728. TreeWalker: DomTreeWalker,
  29729. TextSeeker,
  29730. DOMUtils,
  29731. ScriptLoader,
  29732. RangeUtils,
  29733. Serializer: DomSerializer,
  29734. StyleSheetLoader,
  29735. ControlSelection,
  29736. BookmarkManager,
  29737. Selection: EditorSelection,
  29738. Event: EventUtils.Event
  29739. },
  29740. html: {
  29741. Styles,
  29742. Entities,
  29743. Node: AstNode,
  29744. Schema,
  29745. DomParser,
  29746. Writer,
  29747. Serializer: HtmlSerializer
  29748. },
  29749. Env,
  29750. AddOnManager,
  29751. Annotator,
  29752. Formatter,
  29753. UndoManager,
  29754. EditorCommands,
  29755. WindowManager,
  29756. NotificationManager,
  29757. EditorObservable,
  29758. Shortcuts,
  29759. Editor,
  29760. FocusManager,
  29761. EditorManager,
  29762. DOM: DOMUtils.DOM,
  29763. ScriptLoader: ScriptLoader.ScriptLoader,
  29764. PluginManager,
  29765. ThemeManager,
  29766. ModelManager,
  29767. IconManager,
  29768. Resource,
  29769. FakeClipboard,
  29770. trim: Tools.trim,
  29771. isArray: Tools.isArray,
  29772. is: Tools.is,
  29773. toArray: Tools.toArray,
  29774. makeMap: Tools.makeMap,
  29775. each: Tools.each,
  29776. map: Tools.map,
  29777. grep: Tools.grep,
  29778. inArray: Tools.inArray,
  29779. extend: Tools.extend,
  29780. walk: Tools.walk,
  29781. resolve: Tools.resolve,
  29782. explode: Tools.explode,
  29783. _addCacheSuffix: Tools._addCacheSuffix
  29784. };
  29785. const tinymce = Tools.extend(EditorManager, publicApi);
  29786. const exportToModuleLoaders = tinymce => {
  29787. if (typeof module === 'object') {
  29788. try {
  29789. module.exports = tinymce;
  29790. } catch (_) {
  29791. }
  29792. }
  29793. };
  29794. const exportToWindowGlobal = tinymce => {
  29795. window.tinymce = tinymce;
  29796. window.tinyMCE = tinymce;
  29797. };
  29798. exportToWindowGlobal(tinymce);
  29799. exportToModuleLoaders(tinymce);
  29800. })();