plugin.js 117 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462
  1. /**
  2. * TinyMCE version 6.8.6 (TBD)
  3. */
  4. (function () {
  5. 'use strict';
  6. var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');
  7. const hasProto = (v, constructor, predicate) => {
  8. var _a;
  9. if (predicate(v, constructor.prototype)) {
  10. return true;
  11. } else {
  12. return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;
  13. }
  14. };
  15. const typeOf = x => {
  16. const t = typeof x;
  17. if (x === null) {
  18. return 'null';
  19. } else if (t === 'object' && Array.isArray(x)) {
  20. return 'array';
  21. } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {
  22. return 'string';
  23. } else {
  24. return t;
  25. }
  26. };
  27. const isType$1 = type => value => typeOf(value) === type;
  28. const isSimpleType = type => value => typeof value === type;
  29. const eq$1 = t => a => t === a;
  30. const isString = isType$1('string');
  31. const isArray = isType$1('array');
  32. const isBoolean = isSimpleType('boolean');
  33. const isUndefined = eq$1(undefined);
  34. const isNullable = a => a === null || a === undefined;
  35. const isNonNullable = a => !isNullable(a);
  36. const isFunction = isSimpleType('function');
  37. const isNumber = isSimpleType('number');
  38. const noop = () => {
  39. };
  40. const compose1 = (fbc, fab) => a => fbc(fab(a));
  41. const constant = value => {
  42. return () => {
  43. return value;
  44. };
  45. };
  46. const identity = x => {
  47. return x;
  48. };
  49. const tripleEquals = (a, b) => {
  50. return a === b;
  51. };
  52. function curry(fn, ...initialArgs) {
  53. return (...restArgs) => {
  54. const all = initialArgs.concat(restArgs);
  55. return fn.apply(null, all);
  56. };
  57. }
  58. const call = f => {
  59. f();
  60. };
  61. const never = constant(false);
  62. const always = constant(true);
  63. class Optional {
  64. constructor(tag, value) {
  65. this.tag = tag;
  66. this.value = value;
  67. }
  68. static some(value) {
  69. return new Optional(true, value);
  70. }
  71. static none() {
  72. return Optional.singletonNone;
  73. }
  74. fold(onNone, onSome) {
  75. if (this.tag) {
  76. return onSome(this.value);
  77. } else {
  78. return onNone();
  79. }
  80. }
  81. isSome() {
  82. return this.tag;
  83. }
  84. isNone() {
  85. return !this.tag;
  86. }
  87. map(mapper) {
  88. if (this.tag) {
  89. return Optional.some(mapper(this.value));
  90. } else {
  91. return Optional.none();
  92. }
  93. }
  94. bind(binder) {
  95. if (this.tag) {
  96. return binder(this.value);
  97. } else {
  98. return Optional.none();
  99. }
  100. }
  101. exists(predicate) {
  102. return this.tag && predicate(this.value);
  103. }
  104. forall(predicate) {
  105. return !this.tag || predicate(this.value);
  106. }
  107. filter(predicate) {
  108. if (!this.tag || predicate(this.value)) {
  109. return this;
  110. } else {
  111. return Optional.none();
  112. }
  113. }
  114. getOr(replacement) {
  115. return this.tag ? this.value : replacement;
  116. }
  117. or(replacement) {
  118. return this.tag ? this : replacement;
  119. }
  120. getOrThunk(thunk) {
  121. return this.tag ? this.value : thunk();
  122. }
  123. orThunk(thunk) {
  124. return this.tag ? this : thunk();
  125. }
  126. getOrDie(message) {
  127. if (!this.tag) {
  128. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  129. } else {
  130. return this.value;
  131. }
  132. }
  133. static from(value) {
  134. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  135. }
  136. getOrNull() {
  137. return this.tag ? this.value : null;
  138. }
  139. getOrUndefined() {
  140. return this.value;
  141. }
  142. each(worker) {
  143. if (this.tag) {
  144. worker(this.value);
  145. }
  146. }
  147. toArray() {
  148. return this.tag ? [this.value] : [];
  149. }
  150. toString() {
  151. return this.tag ? `some(${ this.value })` : 'none()';
  152. }
  153. }
  154. Optional.singletonNone = new Optional(false);
  155. const keys = Object.keys;
  156. const hasOwnProperty = Object.hasOwnProperty;
  157. const each$1 = (obj, f) => {
  158. const props = keys(obj);
  159. for (let k = 0, len = props.length; k < len; k++) {
  160. const i = props[k];
  161. const x = obj[i];
  162. f(x, i);
  163. }
  164. };
  165. const objAcc = r => (x, i) => {
  166. r[i] = x;
  167. };
  168. const internalFilter = (obj, pred, onTrue, onFalse) => {
  169. each$1(obj, (x, i) => {
  170. (pred(x, i) ? onTrue : onFalse)(x, i);
  171. });
  172. };
  173. const filter$1 = (obj, pred) => {
  174. const t = {};
  175. internalFilter(obj, pred, objAcc(t), noop);
  176. return t;
  177. };
  178. const mapToArray = (obj, f) => {
  179. const r = [];
  180. each$1(obj, (value, name) => {
  181. r.push(f(value, name));
  182. });
  183. return r;
  184. };
  185. const values = obj => {
  186. return mapToArray(obj, identity);
  187. };
  188. const size = obj => {
  189. return keys(obj).length;
  190. };
  191. const get$4 = (obj, key) => {
  192. return has(obj, key) ? Optional.from(obj[key]) : Optional.none();
  193. };
  194. const has = (obj, key) => hasOwnProperty.call(obj, key);
  195. const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;
  196. const isEmpty$1 = r => {
  197. for (const x in r) {
  198. if (hasOwnProperty.call(r, x)) {
  199. return false;
  200. }
  201. }
  202. return true;
  203. };
  204. const nativeIndexOf = Array.prototype.indexOf;
  205. const nativePush = Array.prototype.push;
  206. const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  207. const contains = (xs, x) => rawIndexOf(xs, x) > -1;
  208. const exists = (xs, pred) => {
  209. for (let i = 0, len = xs.length; i < len; i++) {
  210. const x = xs[i];
  211. if (pred(x, i)) {
  212. return true;
  213. }
  214. }
  215. return false;
  216. };
  217. const range = (num, f) => {
  218. const r = [];
  219. for (let i = 0; i < num; i++) {
  220. r.push(f(i));
  221. }
  222. return r;
  223. };
  224. const map = (xs, f) => {
  225. const len = xs.length;
  226. const r = new Array(len);
  227. for (let i = 0; i < len; i++) {
  228. const x = xs[i];
  229. r[i] = f(x, i);
  230. }
  231. return r;
  232. };
  233. const each = (xs, f) => {
  234. for (let i = 0, len = xs.length; i < len; i++) {
  235. const x = xs[i];
  236. f(x, i);
  237. }
  238. };
  239. const eachr = (xs, f) => {
  240. for (let i = xs.length - 1; i >= 0; i--) {
  241. const x = xs[i];
  242. f(x, i);
  243. }
  244. };
  245. const partition = (xs, pred) => {
  246. const pass = [];
  247. const fail = [];
  248. for (let i = 0, len = xs.length; i < len; i++) {
  249. const x = xs[i];
  250. const arr = pred(x, i) ? pass : fail;
  251. arr.push(x);
  252. }
  253. return {
  254. pass,
  255. fail
  256. };
  257. };
  258. const filter = (xs, pred) => {
  259. const r = [];
  260. for (let i = 0, len = xs.length; i < len; i++) {
  261. const x = xs[i];
  262. if (pred(x, i)) {
  263. r.push(x);
  264. }
  265. }
  266. return r;
  267. };
  268. const foldr = (xs, f, acc) => {
  269. eachr(xs, (x, i) => {
  270. acc = f(acc, x, i);
  271. });
  272. return acc;
  273. };
  274. const foldl = (xs, f, acc) => {
  275. each(xs, (x, i) => {
  276. acc = f(acc, x, i);
  277. });
  278. return acc;
  279. };
  280. const findUntil = (xs, pred, until) => {
  281. for (let i = 0, len = xs.length; i < len; i++) {
  282. const x = xs[i];
  283. if (pred(x, i)) {
  284. return Optional.some(x);
  285. } else if (until(x, i)) {
  286. break;
  287. }
  288. }
  289. return Optional.none();
  290. };
  291. const find = (xs, pred) => {
  292. return findUntil(xs, pred, never);
  293. };
  294. const flatten$1 = xs => {
  295. const r = [];
  296. for (let i = 0, len = xs.length; i < len; ++i) {
  297. if (!isArray(xs[i])) {
  298. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  299. }
  300. nativePush.apply(r, xs[i]);
  301. }
  302. return r;
  303. };
  304. const bind = (xs, f) => flatten$1(map(xs, f));
  305. const forall = (xs, pred) => {
  306. for (let i = 0, len = xs.length; i < len; ++i) {
  307. const x = xs[i];
  308. if (pred(x, i) !== true) {
  309. return false;
  310. }
  311. }
  312. return true;
  313. };
  314. const mapToObject = (xs, f) => {
  315. const r = {};
  316. for (let i = 0, len = xs.length; i < len; i++) {
  317. const x = xs[i];
  318. r[String(x)] = f(x, i);
  319. }
  320. return r;
  321. };
  322. const get$3 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  323. const head = xs => get$3(xs, 0);
  324. const last = xs => get$3(xs, xs.length - 1);
  325. const findMap = (arr, f) => {
  326. for (let i = 0; i < arr.length; i++) {
  327. const r = f(arr[i], i);
  328. if (r.isSome()) {
  329. return r;
  330. }
  331. }
  332. return Optional.none();
  333. };
  334. const COMMENT = 8;
  335. const DOCUMENT = 9;
  336. const DOCUMENT_FRAGMENT = 11;
  337. const ELEMENT = 1;
  338. const TEXT = 3;
  339. const fromHtml = (html, scope) => {
  340. const doc = scope || document;
  341. const div = doc.createElement('div');
  342. div.innerHTML = html;
  343. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  344. const message = 'HTML does not have a single root node';
  345. console.error(message, html);
  346. throw new Error(message);
  347. }
  348. return fromDom$1(div.childNodes[0]);
  349. };
  350. const fromTag = (tag, scope) => {
  351. const doc = scope || document;
  352. const node = doc.createElement(tag);
  353. return fromDom$1(node);
  354. };
  355. const fromText = (text, scope) => {
  356. const doc = scope || document;
  357. const node = doc.createTextNode(text);
  358. return fromDom$1(node);
  359. };
  360. const fromDom$1 = node => {
  361. if (node === null || node === undefined) {
  362. throw new Error('Node cannot be null or undefined');
  363. }
  364. return { dom: node };
  365. };
  366. const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
  367. const SugarElement = {
  368. fromHtml,
  369. fromTag,
  370. fromText,
  371. fromDom: fromDom$1,
  372. fromPoint
  373. };
  374. const is$2 = (element, selector) => {
  375. const dom = element.dom;
  376. if (dom.nodeType !== ELEMENT) {
  377. return false;
  378. } else {
  379. const elem = dom;
  380. if (elem.matches !== undefined) {
  381. return elem.matches(selector);
  382. } else if (elem.msMatchesSelector !== undefined) {
  383. return elem.msMatchesSelector(selector);
  384. } else if (elem.webkitMatchesSelector !== undefined) {
  385. return elem.webkitMatchesSelector(selector);
  386. } else if (elem.mozMatchesSelector !== undefined) {
  387. return elem.mozMatchesSelector(selector);
  388. } else {
  389. throw new Error('Browser lacks native selectors');
  390. }
  391. }
  392. };
  393. const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;
  394. const all$1 = (selector, scope) => {
  395. const base = scope === undefined ? document : scope.dom;
  396. return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);
  397. };
  398. const one = (selector, scope) => {
  399. const base = scope === undefined ? document : scope.dom;
  400. return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);
  401. };
  402. const eq = (e1, e2) => e1.dom === e2.dom;
  403. const is$1 = is$2;
  404. typeof window !== 'undefined' ? window : Function('return this;')();
  405. const name = element => {
  406. const r = element.dom.nodeName;
  407. return r.toLowerCase();
  408. };
  409. const type = element => element.dom.nodeType;
  410. const isType = t => element => type(element) === t;
  411. const isComment = element => type(element) === COMMENT || name(element) === '#comment';
  412. const isElement = isType(ELEMENT);
  413. const isText = isType(TEXT);
  414. const isDocument = isType(DOCUMENT);
  415. const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  416. const isTag = tag => e => isElement(e) && name(e) === tag;
  417. const owner = element => SugarElement.fromDom(element.dom.ownerDocument);
  418. const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);
  419. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  420. const parents = (element, isRoot) => {
  421. const stop = isFunction(isRoot) ? isRoot : never;
  422. let dom = element.dom;
  423. const ret = [];
  424. while (dom.parentNode !== null && dom.parentNode !== undefined) {
  425. const rawParent = dom.parentNode;
  426. const p = SugarElement.fromDom(rawParent);
  427. ret.push(p);
  428. if (stop(p) === true) {
  429. break;
  430. } else {
  431. dom = rawParent;
  432. }
  433. }
  434. return ret;
  435. };
  436. const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);
  437. const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  438. const children$3 = element => map(element.dom.childNodes, SugarElement.fromDom);
  439. const child$3 = (element, index) => {
  440. const cs = element.dom.childNodes;
  441. return Optional.from(cs[index]).map(SugarElement.fromDom);
  442. };
  443. const firstChild = element => child$3(element, 0);
  444. const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  445. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  446. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  447. const getShadowRoot = e => {
  448. const r = getRootNode(e);
  449. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  450. };
  451. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  452. const inBody = element => {
  453. const dom = isText(element) ? element.dom.parentNode : element.dom;
  454. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  455. return false;
  456. }
  457. const doc = dom.ownerDocument;
  458. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  459. };
  460. var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
  461. if (is(scope, a)) {
  462. return Optional.some(scope);
  463. } else if (isFunction(isRoot) && isRoot(scope)) {
  464. return Optional.none();
  465. } else {
  466. return ancestor(scope, a, isRoot);
  467. }
  468. };
  469. const ancestor$1 = (scope, predicate, isRoot) => {
  470. let element = scope.dom;
  471. const stop = isFunction(isRoot) ? isRoot : never;
  472. while (element.parentNode) {
  473. element = element.parentNode;
  474. const el = SugarElement.fromDom(element);
  475. if (predicate(el)) {
  476. return Optional.some(el);
  477. } else if (stop(el)) {
  478. break;
  479. }
  480. }
  481. return Optional.none();
  482. };
  483. const closest$2 = (scope, predicate, isRoot) => {
  484. const is = (s, test) => test(s);
  485. return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);
  486. };
  487. const child$2 = (scope, predicate) => {
  488. const pred = node => predicate(SugarElement.fromDom(node));
  489. const result = find(scope.dom.childNodes, pred);
  490. return result.map(SugarElement.fromDom);
  491. };
  492. const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is$2(e, selector), isRoot);
  493. const child$1 = (scope, selector) => child$2(scope, e => is$2(e, selector));
  494. const descendant = (scope, selector) => one(selector, scope);
  495. const closest$1 = (scope, selector, isRoot) => {
  496. const is = (element, selector) => is$2(element, selector);
  497. return ClosestOrAncestor(is, ancestor, scope, selector, isRoot);
  498. };
  499. const closest = target => closest$1(target, '[contenteditable]');
  500. const isEditable = (element, assumeEditable = false) => {
  501. if (inBody(element)) {
  502. return element.dom.isContentEditable;
  503. } else {
  504. return closest(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');
  505. }
  506. };
  507. const getRaw$1 = element => element.dom.contentEditable;
  508. const getNodeName = elm => elm.nodeName.toLowerCase();
  509. const getBody = editor => SugarElement.fromDom(editor.getBody());
  510. const getIsRoot = editor => element => eq(element, getBody(editor));
  511. const removePxSuffix = size => size ? size.replace(/px$/, '') : '';
  512. const addPxSuffix = size => /^\d+(\.\d+)?$/.test(size) ? size + 'px' : size;
  513. const getSelectionStart = editor => SugarElement.fromDom(editor.selection.getStart());
  514. const getSelectionEnd = editor => SugarElement.fromDom(editor.selection.getEnd());
  515. const isInEditableContext = cell => closest$2(cell, isTag('table')).forall(isEditable);
  516. const children$2 = (scope, predicate) => filter(children$3(scope), predicate);
  517. const descendants$1 = (scope, predicate) => {
  518. let result = [];
  519. each(children$3(scope), x => {
  520. if (predicate(x)) {
  521. result = result.concat([x]);
  522. }
  523. result = result.concat(descendants$1(x, predicate));
  524. });
  525. return result;
  526. };
  527. const children$1 = (scope, selector) => children$2(scope, e => is$2(e, selector));
  528. const descendants = (scope, selector) => all$1(selector, scope);
  529. const rawSet = (dom, key, value) => {
  530. if (isString(value) || isBoolean(value) || isNumber(value)) {
  531. dom.setAttribute(key, value + '');
  532. } else {
  533. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  534. throw new Error('Attribute value was not simple');
  535. }
  536. };
  537. const set$2 = (element, key, value) => {
  538. rawSet(element.dom, key, value);
  539. };
  540. const setAll = (element, attrs) => {
  541. const dom = element.dom;
  542. each$1(attrs, (v, k) => {
  543. rawSet(dom, k, v);
  544. });
  545. };
  546. const get$2 = (element, key) => {
  547. const v = element.dom.getAttribute(key);
  548. return v === null ? undefined : v;
  549. };
  550. const getOpt = (element, key) => Optional.from(get$2(element, key));
  551. const remove$2 = (element, key) => {
  552. element.dom.removeAttribute(key);
  553. };
  554. const clone = element => foldl(element.dom.attributes, (acc, attr) => {
  555. acc[attr.name] = attr.value;
  556. return acc;
  557. }, {});
  558. const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  559. const cat = arr => {
  560. const r = [];
  561. const push = x => {
  562. r.push(x);
  563. };
  564. for (let i = 0; i < arr.length; i++) {
  565. arr[i].each(push);
  566. }
  567. return r;
  568. };
  569. const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  570. const flatten = oot => oot.bind(identity);
  571. const someIf = (b, a) => b ? Optional.some(a) : Optional.none();
  572. const removeFromStart = (str, numChars) => {
  573. return str.substring(numChars);
  574. };
  575. const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;
  576. const removeLeading = (str, prefix) => {
  577. return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;
  578. };
  579. const startsWith = (str, prefix) => {
  580. return checkRange(str, prefix, 0);
  581. };
  582. const blank = r => s => s.replace(r, '');
  583. const trim = blank(/^\s+|\s+$/g);
  584. const isNotEmpty = s => s.length > 0;
  585. const isEmpty = s => !isNotEmpty(s);
  586. const toInt = (value, radix = 10) => {
  587. const num = parseInt(value, radix);
  588. return isNaN(num) ? Optional.none() : Optional.some(num);
  589. };
  590. const toFloat = value => {
  591. const num = parseFloat(value);
  592. return isNaN(num) ? Optional.none() : Optional.some(num);
  593. };
  594. const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  595. const internalSet = (dom, property, value) => {
  596. if (!isString(value)) {
  597. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  598. throw new Error('CSS value must be a string: ' + value);
  599. }
  600. if (isSupported(dom)) {
  601. dom.style.setProperty(property, value);
  602. }
  603. };
  604. const internalRemove = (dom, property) => {
  605. if (isSupported(dom)) {
  606. dom.style.removeProperty(property);
  607. }
  608. };
  609. const set$1 = (element, property, value) => {
  610. const dom = element.dom;
  611. internalSet(dom, property, value);
  612. };
  613. const get$1 = (element, property) => {
  614. const dom = element.dom;
  615. const styles = window.getComputedStyle(dom);
  616. const r = styles.getPropertyValue(property);
  617. return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;
  618. };
  619. const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';
  620. const getRaw = (element, property) => {
  621. const dom = element.dom;
  622. const raw = getUnsafeProperty(dom, property);
  623. return Optional.from(raw).filter(r => r.length > 0);
  624. };
  625. const remove$1 = (element, property) => {
  626. const dom = element.dom;
  627. internalRemove(dom, property);
  628. if (is(getOpt(element, 'style').map(trim), '')) {
  629. remove$2(element, 'style');
  630. }
  631. };
  632. const getAttrValue = (cell, name, fallback = 0) => getOpt(cell, name).map(value => parseInt(value, 10)).getOr(fallback);
  633. const firstLayer = (scope, selector) => {
  634. return filterFirstLayer(scope, selector, always);
  635. };
  636. const filterFirstLayer = (scope, selector, predicate) => {
  637. return bind(children$3(scope), x => {
  638. if (is$2(x, selector)) {
  639. return predicate(x) ? [x] : [];
  640. } else {
  641. return filterFirstLayer(x, selector, predicate);
  642. }
  643. });
  644. };
  645. const validSectionList = [
  646. 'tfoot',
  647. 'thead',
  648. 'tbody',
  649. 'colgroup'
  650. ];
  651. const isValidSection = parentName => contains(validSectionList, parentName);
  652. const grid = (rows, columns) => ({
  653. rows,
  654. columns
  655. });
  656. const detail = (element, rowspan, colspan) => ({
  657. element,
  658. rowspan,
  659. colspan
  660. });
  661. const extended = (element, rowspan, colspan, row, column, isLocked) => ({
  662. element,
  663. rowspan,
  664. colspan,
  665. row,
  666. column,
  667. isLocked
  668. });
  669. const rowdetail = (element, cells, section) => ({
  670. element,
  671. cells,
  672. section
  673. });
  674. const bounds = (startRow, startCol, finishRow, finishCol) => ({
  675. startRow,
  676. startCol,
  677. finishRow,
  678. finishCol
  679. });
  680. const columnext = (element, colspan, column) => ({
  681. element,
  682. colspan,
  683. column
  684. });
  685. const colgroup = (element, columns) => ({
  686. element,
  687. columns
  688. });
  689. const lookup = (tags, element, isRoot = never) => {
  690. if (isRoot(element)) {
  691. return Optional.none();
  692. }
  693. if (contains(tags, name(element))) {
  694. return Optional.some(element);
  695. }
  696. const isRootOrUpperTable = elm => is$2(elm, 'table') || isRoot(elm);
  697. return ancestor(element, tags.join(','), isRootOrUpperTable);
  698. };
  699. const cell = (element, isRoot) => lookup([
  700. 'td',
  701. 'th'
  702. ], element, isRoot);
  703. const cells = ancestor => firstLayer(ancestor, 'th,td');
  704. const columns = ancestor => {
  705. if (is$2(ancestor, 'colgroup')) {
  706. return children$1(ancestor, 'col');
  707. } else {
  708. return bind(columnGroups(ancestor), columnGroup => children$1(columnGroup, 'col'));
  709. }
  710. };
  711. const table = (element, isRoot) => closest$1(element, 'table', isRoot);
  712. const rows = ancestor => firstLayer(ancestor, 'tr');
  713. const columnGroups = ancestor => table(ancestor).fold(constant([]), table => children$1(table, 'colgroup'));
  714. const fromRowsOrColGroups = (elems, getSection) => map(elems, row => {
  715. if (name(row) === 'colgroup') {
  716. const cells = map(columns(row), column => {
  717. const colspan = getAttrValue(column, 'span', 1);
  718. return detail(column, 1, colspan);
  719. });
  720. return rowdetail(row, cells, 'colgroup');
  721. } else {
  722. const cells$1 = map(cells(row), cell => {
  723. const rowspan = getAttrValue(cell, 'rowspan', 1);
  724. const colspan = getAttrValue(cell, 'colspan', 1);
  725. return detail(cell, rowspan, colspan);
  726. });
  727. return rowdetail(row, cells$1, getSection(row));
  728. }
  729. });
  730. const getParentSection = group => parent(group).map(parent => {
  731. const parentName = name(parent);
  732. return isValidSection(parentName) ? parentName : 'tbody';
  733. }).getOr('tbody');
  734. const fromTable$1 = table => {
  735. const rows$1 = rows(table);
  736. const columnGroups$1 = columnGroups(table);
  737. const elems = [
  738. ...columnGroups$1,
  739. ...rows$1
  740. ];
  741. return fromRowsOrColGroups(elems, getParentSection);
  742. };
  743. const LOCKED_COL_ATTR = 'data-snooker-locked-cols';
  744. const getLockedColumnsFromTable = table => getOpt(table, LOCKED_COL_ATTR).bind(lockedColStr => Optional.from(lockedColStr.match(/\d+/g))).map(lockedCols => mapToObject(lockedCols, always));
  745. const key = (row, column) => {
  746. return row + ',' + column;
  747. };
  748. const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]);
  749. const findItem = (warehouse, item, comparator) => {
  750. const filtered = filterItems(warehouse, detail => {
  751. return comparator(item, detail.element);
  752. });
  753. return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none();
  754. };
  755. const filterItems = (warehouse, predicate) => {
  756. const all = bind(warehouse.all, r => {
  757. return r.cells;
  758. });
  759. return filter(all, predicate);
  760. };
  761. const generateColumns = rowData => {
  762. const columnsGroup = {};
  763. let index = 0;
  764. each(rowData.cells, column => {
  765. const colspan = column.colspan;
  766. range(colspan, columnIndex => {
  767. const colIndex = index + columnIndex;
  768. columnsGroup[colIndex] = columnext(column.element, colspan, colIndex);
  769. });
  770. index += colspan;
  771. });
  772. return columnsGroup;
  773. };
  774. const generate$1 = list => {
  775. const access = {};
  776. const cells = [];
  777. const tableOpt = head(list).map(rowData => rowData.element).bind(table);
  778. const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({});
  779. let maxRows = 0;
  780. let maxColumns = 0;
  781. let rowCount = 0;
  782. const {
  783. pass: colgroupRows,
  784. fail: rows
  785. } = partition(list, rowData => rowData.section === 'colgroup');
  786. each(rows, rowData => {
  787. const currentRow = [];
  788. each(rowData.cells, rowCell => {
  789. let start = 0;
  790. while (access[key(rowCount, start)] !== undefined) {
  791. start++;
  792. }
  793. const isLocked = hasNonNullableKey(lockedColumns, start.toString());
  794. const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked);
  795. for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) {
  796. for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) {
  797. const rowPosition = rowCount + occupiedRowPosition;
  798. const columnPosition = start + occupiedColumnPosition;
  799. const newpos = key(rowPosition, columnPosition);
  800. access[newpos] = current;
  801. maxColumns = Math.max(maxColumns, columnPosition + 1);
  802. }
  803. }
  804. currentRow.push(current);
  805. });
  806. maxRows++;
  807. cells.push(rowdetail(rowData.element, currentRow, rowData.section));
  808. rowCount++;
  809. });
  810. const {columns, colgroups} = last(colgroupRows).map(rowData => {
  811. const columns = generateColumns(rowData);
  812. const colgroup$1 = colgroup(rowData.element, values(columns));
  813. return {
  814. colgroups: [colgroup$1],
  815. columns
  816. };
  817. }).getOrThunk(() => ({
  818. colgroups: [],
  819. columns: {}
  820. }));
  821. const grid$1 = grid(maxRows, maxColumns);
  822. return {
  823. grid: grid$1,
  824. access,
  825. all: cells,
  826. columns,
  827. colgroups
  828. };
  829. };
  830. const fromTable = table => {
  831. const list = fromTable$1(table);
  832. return generate$1(list);
  833. };
  834. const justCells = warehouse => bind(warehouse.all, w => w.cells);
  835. const justColumns = warehouse => values(warehouse.columns);
  836. const hasColumns = warehouse => keys(warehouse.columns).length > 0;
  837. const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]);
  838. const Warehouse = {
  839. fromTable,
  840. generate: generate$1,
  841. getAt,
  842. findItem,
  843. filterItems,
  844. justCells,
  845. justColumns,
  846. hasColumns,
  847. getColumnAt
  848. };
  849. var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  850. const getTDTHOverallStyle = (dom, elm, name) => {
  851. const cells = dom.select('td,th', elm);
  852. let firstChildStyle;
  853. for (let i = 0; i < cells.length; i++) {
  854. const currentStyle = dom.getStyle(cells[i], name);
  855. if (isUndefined(firstChildStyle)) {
  856. firstChildStyle = currentStyle;
  857. }
  858. if (firstChildStyle !== currentStyle) {
  859. return '';
  860. }
  861. }
  862. return firstChildStyle;
  863. };
  864. const setAlign = (editor, elm, name) => {
  865. global$2.each('left center right'.split(' '), align => {
  866. if (align !== name) {
  867. editor.formatter.remove('align' + align, {}, elm);
  868. }
  869. });
  870. if (name) {
  871. editor.formatter.apply('align' + name, {}, elm);
  872. }
  873. };
  874. const setVAlign = (editor, elm, name) => {
  875. global$2.each('top middle bottom'.split(' '), align => {
  876. if (align !== name) {
  877. editor.formatter.remove('valign' + align, {}, elm);
  878. }
  879. });
  880. if (name) {
  881. editor.formatter.apply('valign' + name, {}, elm);
  882. }
  883. };
  884. const fireTableModified = (editor, table, data) => {
  885. editor.dispatch('TableModified', {
  886. ...data,
  887. table
  888. });
  889. };
  890. const toNumber = (px, fallback) => toFloat(px).getOr(fallback);
  891. const getProp = (element, name, fallback) => toNumber(get$1(element, name), fallback);
  892. const calcContentBoxSize = (element, size, upper, lower) => {
  893. const paddingUpper = getProp(element, `padding-${ upper }`, 0);
  894. const paddingLower = getProp(element, `padding-${ lower }`, 0);
  895. const borderUpper = getProp(element, `border-${ upper }-width`, 0);
  896. const borderLower = getProp(element, `border-${ lower }-width`, 0);
  897. return size - paddingUpper - paddingLower - borderUpper - borderLower;
  898. };
  899. const getCalculatedWidth = (element, boxSizing) => {
  900. const dom = element.dom;
  901. const width = dom.getBoundingClientRect().width || dom.offsetWidth;
  902. return boxSizing === 'border-box' ? width : calcContentBoxSize(element, width, 'left', 'right');
  903. };
  904. const getInnerWidth = element => getCalculatedWidth(element, 'content-box');
  905. const getInner = getInnerWidth;
  906. var global$1 = tinymce.util.Tools.resolve('tinymce.Env');
  907. const defaultTableToolbar = 'tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol';
  908. const defaultCellBorderWidths = range(5, i => {
  909. const size = `${ i + 1 }px`;
  910. return {
  911. title: size,
  912. value: size
  913. };
  914. });
  915. const defaultCellBorderStyles = map([
  916. 'Solid',
  917. 'Dotted',
  918. 'Dashed',
  919. 'Double',
  920. 'Groove',
  921. 'Ridge',
  922. 'Inset',
  923. 'Outset',
  924. 'None',
  925. 'Hidden'
  926. ], type => {
  927. return {
  928. title: type,
  929. value: type.toLowerCase()
  930. };
  931. });
  932. const defaultWidth = '100%';
  933. const getPixelForcedWidth = editor => {
  934. var _a;
  935. const dom = editor.dom;
  936. const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody();
  937. return getInner(SugarElement.fromDom(parentBlock)) + 'px';
  938. };
  939. const determineDefaultStyles = (editor, defaultStyles) => {
  940. if (isResponsiveForced(editor) || !shouldStyleWithCss(editor)) {
  941. return defaultStyles;
  942. } else if (isPixelsForced(editor)) {
  943. return {
  944. ...defaultStyles,
  945. width: getPixelForcedWidth(editor)
  946. };
  947. } else {
  948. return {
  949. ...defaultStyles,
  950. width: defaultWidth
  951. };
  952. }
  953. };
  954. const determineDefaultAttributes = (editor, defaultAttributes) => {
  955. if (isResponsiveForced(editor) || shouldStyleWithCss(editor)) {
  956. return defaultAttributes;
  957. } else if (isPixelsForced(editor)) {
  958. return {
  959. ...defaultAttributes,
  960. width: getPixelForcedWidth(editor)
  961. };
  962. } else {
  963. return {
  964. ...defaultAttributes,
  965. width: defaultWidth
  966. };
  967. }
  968. };
  969. const option = name => editor => editor.options.get(name);
  970. const register = editor => {
  971. const registerOption = editor.options.register;
  972. registerOption('table_border_widths', {
  973. processor: 'object[]',
  974. default: defaultCellBorderWidths
  975. });
  976. registerOption('table_border_styles', {
  977. processor: 'object[]',
  978. default: defaultCellBorderStyles
  979. });
  980. registerOption('table_cell_advtab', {
  981. processor: 'boolean',
  982. default: true
  983. });
  984. registerOption('table_row_advtab', {
  985. processor: 'boolean',
  986. default: true
  987. });
  988. registerOption('table_advtab', {
  989. processor: 'boolean',
  990. default: true
  991. });
  992. registerOption('table_appearance_options', {
  993. processor: 'boolean',
  994. default: true
  995. });
  996. registerOption('table_grid', {
  997. processor: 'boolean',
  998. default: !global$1.deviceType.isTouch()
  999. });
  1000. registerOption('table_cell_class_list', {
  1001. processor: 'object[]',
  1002. default: []
  1003. });
  1004. registerOption('table_row_class_list', {
  1005. processor: 'object[]',
  1006. default: []
  1007. });
  1008. registerOption('table_class_list', {
  1009. processor: 'object[]',
  1010. default: []
  1011. });
  1012. registerOption('table_toolbar', {
  1013. processor: 'string',
  1014. default: defaultTableToolbar
  1015. });
  1016. registerOption('table_background_color_map', {
  1017. processor: 'object[]',
  1018. default: []
  1019. });
  1020. registerOption('table_border_color_map', {
  1021. processor: 'object[]',
  1022. default: []
  1023. });
  1024. };
  1025. const getTableSizingMode = option('table_sizing_mode');
  1026. const getTableBorderWidths = option('table_border_widths');
  1027. const getTableBorderStyles = option('table_border_styles');
  1028. const hasAdvancedCellTab = option('table_cell_advtab');
  1029. const hasAdvancedRowTab = option('table_row_advtab');
  1030. const hasAdvancedTableTab = option('table_advtab');
  1031. const hasAppearanceOptions = option('table_appearance_options');
  1032. const hasTableGrid = option('table_grid');
  1033. const shouldStyleWithCss = option('table_style_by_css');
  1034. const getCellClassList = option('table_cell_class_list');
  1035. const getRowClassList = option('table_row_class_list');
  1036. const getTableClassList = option('table_class_list');
  1037. const getToolbar = option('table_toolbar');
  1038. const getTableBackgroundColorMap = option('table_background_color_map');
  1039. const getTableBorderColorMap = option('table_border_color_map');
  1040. const isPixelsForced = editor => getTableSizingMode(editor) === 'fixed';
  1041. const isResponsiveForced = editor => getTableSizingMode(editor) === 'responsive';
  1042. const getDefaultStyles = editor => {
  1043. const options = editor.options;
  1044. const defaultStyles = options.get('table_default_styles');
  1045. return options.isSet('table_default_styles') ? defaultStyles : determineDefaultStyles(editor, defaultStyles);
  1046. };
  1047. const getDefaultAttributes = editor => {
  1048. const options = editor.options;
  1049. const defaultAttributes = options.get('table_default_attributes');
  1050. return options.isSet('table_default_attributes') ? defaultAttributes : determineDefaultAttributes(editor, defaultAttributes);
  1051. };
  1052. const isWithin = (bounds, detail) => {
  1053. return detail.column >= bounds.startCol && detail.column + detail.colspan - 1 <= bounds.finishCol && detail.row >= bounds.startRow && detail.row + detail.rowspan - 1 <= bounds.finishRow;
  1054. };
  1055. const isRectangular = (warehouse, bounds) => {
  1056. let isRect = true;
  1057. const detailIsWithin = curry(isWithin, bounds);
  1058. for (let i = bounds.startRow; i <= bounds.finishRow; i++) {
  1059. for (let j = bounds.startCol; j <= bounds.finishCol; j++) {
  1060. isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin);
  1061. }
  1062. }
  1063. return isRect ? Optional.some(bounds) : Optional.none();
  1064. };
  1065. const getBounds = (detailA, detailB) => {
  1066. return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1));
  1067. };
  1068. const getAnyBox = (warehouse, startCell, finishCell) => {
  1069. const startCoords = Warehouse.findItem(warehouse, startCell, eq);
  1070. const finishCoords = Warehouse.findItem(warehouse, finishCell, eq);
  1071. return startCoords.bind(sc => {
  1072. return finishCoords.map(fc => {
  1073. return getBounds(sc, fc);
  1074. });
  1075. });
  1076. };
  1077. const getBox$1 = (warehouse, startCell, finishCell) => {
  1078. return getAnyBox(warehouse, startCell, finishCell).bind(bounds => {
  1079. return isRectangular(warehouse, bounds);
  1080. });
  1081. };
  1082. const getBox = (table, first, last) => {
  1083. const warehouse = getWarehouse(table);
  1084. return getBox$1(warehouse, first, last);
  1085. };
  1086. const getWarehouse = Warehouse.fromTable;
  1087. const before = (marker, element) => {
  1088. const parent$1 = parent(marker);
  1089. parent$1.each(v => {
  1090. v.dom.insertBefore(element.dom, marker.dom);
  1091. });
  1092. };
  1093. const after$1 = (marker, element) => {
  1094. const sibling = nextSibling(marker);
  1095. sibling.fold(() => {
  1096. const parent$1 = parent(marker);
  1097. parent$1.each(v => {
  1098. append$1(v, element);
  1099. });
  1100. }, v => {
  1101. before(v, element);
  1102. });
  1103. };
  1104. const prepend = (parent, element) => {
  1105. const firstChild$1 = firstChild(parent);
  1106. firstChild$1.fold(() => {
  1107. append$1(parent, element);
  1108. }, v => {
  1109. parent.dom.insertBefore(element.dom, v.dom);
  1110. });
  1111. };
  1112. const append$1 = (parent, element) => {
  1113. parent.dom.appendChild(element.dom);
  1114. };
  1115. const wrap = (element, wrapper) => {
  1116. before(element, wrapper);
  1117. append$1(wrapper, element);
  1118. };
  1119. const after = (marker, elements) => {
  1120. each(elements, (x, i) => {
  1121. const e = i === 0 ? marker : elements[i - 1];
  1122. after$1(e, x);
  1123. });
  1124. };
  1125. const append = (parent, elements) => {
  1126. each(elements, x => {
  1127. append$1(parent, x);
  1128. });
  1129. };
  1130. const remove = element => {
  1131. const dom = element.dom;
  1132. if (dom.parentNode !== null) {
  1133. dom.parentNode.removeChild(dom);
  1134. }
  1135. };
  1136. const unwrap = wrapper => {
  1137. const children = children$3(wrapper);
  1138. if (children.length > 0) {
  1139. after(wrapper, children);
  1140. }
  1141. remove(wrapper);
  1142. };
  1143. const NodeValue = (is, name) => {
  1144. const get = element => {
  1145. if (!is(element)) {
  1146. throw new Error('Can only get ' + name + ' value of a ' + name + ' node');
  1147. }
  1148. return getOption(element).getOr('');
  1149. };
  1150. const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();
  1151. const set = (element, value) => {
  1152. if (!is(element)) {
  1153. throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');
  1154. }
  1155. element.dom.nodeValue = value;
  1156. };
  1157. return {
  1158. get,
  1159. getOption,
  1160. set
  1161. };
  1162. };
  1163. const api = NodeValue(isText, 'text');
  1164. const get = element => api.get(element);
  1165. const set = (element, value) => api.set(element, value);
  1166. var TagBoundaries = [
  1167. 'body',
  1168. 'p',
  1169. 'div',
  1170. 'article',
  1171. 'aside',
  1172. 'figcaption',
  1173. 'figure',
  1174. 'footer',
  1175. 'header',
  1176. 'nav',
  1177. 'section',
  1178. 'ol',
  1179. 'ul',
  1180. 'li',
  1181. 'table',
  1182. 'thead',
  1183. 'tbody',
  1184. 'tfoot',
  1185. 'caption',
  1186. 'tr',
  1187. 'td',
  1188. 'th',
  1189. 'h1',
  1190. 'h2',
  1191. 'h3',
  1192. 'h4',
  1193. 'h5',
  1194. 'h6',
  1195. 'blockquote',
  1196. 'pre',
  1197. 'address'
  1198. ];
  1199. var DomUniverse = () => {
  1200. const clone$1 = element => {
  1201. return SugarElement.fromDom(element.dom.cloneNode(false));
  1202. };
  1203. const document = element => documentOrOwner(element).dom;
  1204. const isBoundary = element => {
  1205. if (!isElement(element)) {
  1206. return false;
  1207. }
  1208. if (name(element) === 'body') {
  1209. return true;
  1210. }
  1211. return contains(TagBoundaries, name(element));
  1212. };
  1213. const isEmptyTag = element => {
  1214. if (!isElement(element)) {
  1215. return false;
  1216. }
  1217. return contains([
  1218. 'br',
  1219. 'img',
  1220. 'hr',
  1221. 'input'
  1222. ], name(element));
  1223. };
  1224. const isNonEditable = element => isElement(element) && get$2(element, 'contenteditable') === 'false';
  1225. const comparePosition = (element, other) => {
  1226. return element.dom.compareDocumentPosition(other.dom);
  1227. };
  1228. const copyAttributesTo = (source, destination) => {
  1229. const as = clone(source);
  1230. setAll(destination, as);
  1231. };
  1232. const isSpecial = element => {
  1233. const tag = name(element);
  1234. return contains([
  1235. 'script',
  1236. 'noscript',
  1237. 'iframe',
  1238. 'noframes',
  1239. 'noembed',
  1240. 'title',
  1241. 'style',
  1242. 'textarea',
  1243. 'xmp'
  1244. ], tag);
  1245. };
  1246. const getLanguage = element => isElement(element) ? getOpt(element, 'lang') : Optional.none();
  1247. return {
  1248. up: constant({
  1249. selector: ancestor,
  1250. closest: closest$1,
  1251. predicate: ancestor$1,
  1252. all: parents
  1253. }),
  1254. down: constant({
  1255. selector: descendants,
  1256. predicate: descendants$1
  1257. }),
  1258. styles: constant({
  1259. get: get$1,
  1260. getRaw: getRaw,
  1261. set: set$1,
  1262. remove: remove$1
  1263. }),
  1264. attrs: constant({
  1265. get: get$2,
  1266. set: set$2,
  1267. remove: remove$2,
  1268. copyTo: copyAttributesTo
  1269. }),
  1270. insert: constant({
  1271. before: before,
  1272. after: after$1,
  1273. afterAll: after,
  1274. append: append$1,
  1275. appendAll: append,
  1276. prepend: prepend,
  1277. wrap: wrap
  1278. }),
  1279. remove: constant({
  1280. unwrap: unwrap,
  1281. remove: remove
  1282. }),
  1283. create: constant({
  1284. nu: SugarElement.fromTag,
  1285. clone: clone$1,
  1286. text: SugarElement.fromText
  1287. }),
  1288. query: constant({
  1289. comparePosition,
  1290. prevSibling: prevSibling,
  1291. nextSibling: nextSibling
  1292. }),
  1293. property: constant({
  1294. children: children$3,
  1295. name: name,
  1296. parent: parent,
  1297. document,
  1298. isText: isText,
  1299. isComment: isComment,
  1300. isElement: isElement,
  1301. isSpecial,
  1302. getLanguage,
  1303. getText: get,
  1304. setText: set,
  1305. isBoundary,
  1306. isEmptyTag,
  1307. isNonEditable
  1308. }),
  1309. eq: eq,
  1310. is: is$1
  1311. };
  1312. };
  1313. const all = (universe, look, elements, f) => {
  1314. const head = elements[0];
  1315. const tail = elements.slice(1);
  1316. return f(universe, look, head, tail);
  1317. };
  1318. const oneAll = (universe, look, elements) => {
  1319. return elements.length > 0 ? all(universe, look, elements, unsafeOne) : Optional.none();
  1320. };
  1321. const unsafeOne = (universe, look, head, tail) => {
  1322. const start = look(universe, head);
  1323. return foldr(tail, (b, a) => {
  1324. const current = look(universe, a);
  1325. return commonElement(universe, b, current);
  1326. }, start);
  1327. };
  1328. const commonElement = (universe, start, end) => {
  1329. return start.bind(s => {
  1330. return end.filter(curry(universe.eq, s));
  1331. });
  1332. };
  1333. const sharedOne$1 = oneAll;
  1334. const universe = DomUniverse();
  1335. const sharedOne = (look, elements) => {
  1336. return sharedOne$1(universe, (_universe, element) => {
  1337. return look(element);
  1338. }, elements);
  1339. };
  1340. const lookupTable = container => {
  1341. return ancestor(container, 'table');
  1342. };
  1343. const retrieve$1 = (container, selector) => {
  1344. const sels = descendants(container, selector);
  1345. return sels.length > 0 ? Optional.some(sels) : Optional.none();
  1346. };
  1347. const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => {
  1348. return descendant(container, firstSelectedSelector).bind(first => {
  1349. return descendant(container, lastSelectedSelector).bind(last => {
  1350. return sharedOne(lookupTable, [
  1351. first,
  1352. last
  1353. ]).map(table => {
  1354. return {
  1355. first,
  1356. last,
  1357. table
  1358. };
  1359. });
  1360. });
  1361. });
  1362. };
  1363. const retrieve = (container, selector) => {
  1364. return retrieve$1(container, selector);
  1365. };
  1366. const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => {
  1367. return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind(edges => {
  1368. const isRoot = ancestor => {
  1369. return eq(container, ancestor);
  1370. };
  1371. const sectionSelector = 'thead,tfoot,tbody,table';
  1372. const firstAncestor = ancestor(edges.first, sectionSelector, isRoot);
  1373. const lastAncestor = ancestor(edges.last, sectionSelector, isRoot);
  1374. return firstAncestor.bind(fA => {
  1375. return lastAncestor.bind(lA => {
  1376. return eq(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none();
  1377. });
  1378. });
  1379. });
  1380. };
  1381. const fromDom = nodes => map(nodes, SugarElement.fromDom);
  1382. const strSelected = 'data-mce-selected';
  1383. const strSelectedSelector = 'td[' + strSelected + '],th[' + strSelected + ']';
  1384. const strFirstSelected = 'data-mce-first-selected';
  1385. const strFirstSelectedSelector = 'td[' + strFirstSelected + '],th[' + strFirstSelected + ']';
  1386. const strLastSelected = 'data-mce-last-selected';
  1387. const strLastSelectedSelector = 'td[' + strLastSelected + '],th[' + strLastSelected + ']';
  1388. const ephemera = {
  1389. selected: strSelected,
  1390. selectedSelector: strSelectedSelector,
  1391. firstSelected: strFirstSelected,
  1392. firstSelectedSelector: strFirstSelectedSelector,
  1393. lastSelected: strLastSelected,
  1394. lastSelectedSelector: strLastSelectedSelector
  1395. };
  1396. const getSelectionCellFallback = element => table(element).bind(table => retrieve(table, ephemera.firstSelectedSelector)).fold(constant(element), cells => cells[0]);
  1397. const getSelectionFromSelector = selector => (initCell, isRoot) => {
  1398. const cellName = name(initCell);
  1399. const cell = cellName === 'col' || cellName === 'colgroup' ? getSelectionCellFallback(initCell) : initCell;
  1400. return closest$1(cell, selector, isRoot);
  1401. };
  1402. const getSelectionCellOrCaption = getSelectionFromSelector('th,td,caption');
  1403. const getSelectionCell = getSelectionFromSelector('th,td');
  1404. const getCellsFromSelection = editor => fromDom(editor.model.table.getSelectedCells());
  1405. const getRowsFromSelection = (selected, selector) => {
  1406. const cellOpt = getSelectionCell(selected);
  1407. const rowsOpt = cellOpt.bind(cell => table(cell)).map(table => rows(table));
  1408. return lift2(cellOpt, rowsOpt, (cell, rows) => filter(rows, row => exists(fromDom(row.dom.cells), rowCell => get$2(rowCell, selector) === '1' || eq(rowCell, cell)))).getOr([]);
  1409. };
  1410. const verticalAlignValues = [
  1411. {
  1412. text: 'None',
  1413. value: ''
  1414. },
  1415. {
  1416. text: 'Top',
  1417. value: 'top'
  1418. },
  1419. {
  1420. text: 'Middle',
  1421. value: 'middle'
  1422. },
  1423. {
  1424. text: 'Bottom',
  1425. value: 'bottom'
  1426. }
  1427. ];
  1428. const hexColour = value => ({ value: normalizeHex(value) });
  1429. const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
  1430. const longformRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
  1431. const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);
  1432. const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();
  1433. const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();
  1434. const toHex = component => {
  1435. const hex = component.toString(16);
  1436. return (hex.length === 1 ? '0' + hex : hex).toUpperCase();
  1437. };
  1438. const fromRgba = rgbaColour => {
  1439. const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);
  1440. return hexColour(value);
  1441. };
  1442. const rgbRegex = /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/i;
  1443. const rgbaRegex = /^\s*rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d?(?:\.\d+)?)\s*\)\s*$/i;
  1444. const rgbaColour = (red, green, blue, alpha) => ({
  1445. red,
  1446. green,
  1447. blue,
  1448. alpha
  1449. });
  1450. const fromStringValues = (red, green, blue, alpha) => {
  1451. const r = parseInt(red, 10);
  1452. const g = parseInt(green, 10);
  1453. const b = parseInt(blue, 10);
  1454. const a = parseFloat(alpha);
  1455. return rgbaColour(r, g, b, a);
  1456. };
  1457. const fromString = rgbaString => {
  1458. if (rgbaString === 'transparent') {
  1459. return Optional.some(rgbaColour(0, 0, 0, 0));
  1460. }
  1461. const rgbMatch = rgbRegex.exec(rgbaString);
  1462. if (rgbMatch !== null) {
  1463. return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));
  1464. }
  1465. const rgbaMatch = rgbaRegex.exec(rgbaString);
  1466. if (rgbaMatch !== null) {
  1467. return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));
  1468. }
  1469. return Optional.none();
  1470. };
  1471. const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {
  1472. const canvas = document.createElement('canvas');
  1473. canvas.height = 1;
  1474. canvas.width = 1;
  1475. const canvasContext = canvas.getContext('2d');
  1476. canvasContext.clearRect(0, 0, canvas.width, canvas.height);
  1477. canvasContext.fillStyle = '#FFFFFF';
  1478. canvasContext.fillStyle = color;
  1479. canvasContext.fillRect(0, 0, 1, 1);
  1480. const rgba = canvasContext.getImageData(0, 0, 1, 1).data;
  1481. const r = rgba[0];
  1482. const g = rgba[1];
  1483. const b = rgba[2];
  1484. const a = rgba[3];
  1485. return fromRgba(rgbaColour(r, g, b, a));
  1486. });
  1487. const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);
  1488. const Cell = initial => {
  1489. let value = initial;
  1490. const get = () => {
  1491. return value;
  1492. };
  1493. const set = v => {
  1494. value = v;
  1495. };
  1496. return {
  1497. get,
  1498. set
  1499. };
  1500. };
  1501. const singleton = doRevoke => {
  1502. const subject = Cell(Optional.none());
  1503. const revoke = () => subject.get().each(doRevoke);
  1504. const clear = () => {
  1505. revoke();
  1506. subject.set(Optional.none());
  1507. };
  1508. const isSet = () => subject.get().isSome();
  1509. const get = () => subject.get();
  1510. const set = s => {
  1511. revoke();
  1512. subject.set(Optional.some(s));
  1513. };
  1514. return {
  1515. clear,
  1516. isSet,
  1517. get,
  1518. set
  1519. };
  1520. };
  1521. const unbindable = () => singleton(s => s.unbind());
  1522. const onSetupToggle = (editor, formatName, formatValue) => {
  1523. return api => {
  1524. const boundCallback = unbindable();
  1525. const isNone = isEmpty(formatValue);
  1526. const init = () => {
  1527. const selectedCells = getCellsFromSelection(editor);
  1528. const checkNode = cell => editor.formatter.match(formatName, { value: formatValue }, cell.dom, isNone);
  1529. if (isNone) {
  1530. api.setActive(!exists(selectedCells, checkNode));
  1531. boundCallback.set(editor.formatter.formatChanged(formatName, match => api.setActive(!match), true));
  1532. } else {
  1533. api.setActive(forall(selectedCells, checkNode));
  1534. boundCallback.set(editor.formatter.formatChanged(formatName, api.setActive, false, { value: formatValue }));
  1535. }
  1536. };
  1537. editor.initialized ? init() : editor.on('init', init);
  1538. return boundCallback.clear;
  1539. };
  1540. };
  1541. const isListGroup = item => hasNonNullableKey(item, 'menu');
  1542. const buildListItems = items => map(items, item => {
  1543. const text = item.text || item.title || '';
  1544. if (isListGroup(item)) {
  1545. return {
  1546. text,
  1547. items: buildListItems(item.menu)
  1548. };
  1549. } else {
  1550. return {
  1551. text,
  1552. value: item.value
  1553. };
  1554. }
  1555. });
  1556. const buildMenuItems = (editor, items, format, onAction) => map(items, item => {
  1557. const text = item.text || item.title;
  1558. if (isListGroup(item)) {
  1559. return {
  1560. type: 'nestedmenuitem',
  1561. text,
  1562. getSubmenuItems: () => buildMenuItems(editor, item.menu, format, onAction)
  1563. };
  1564. } else {
  1565. return {
  1566. text,
  1567. type: 'togglemenuitem',
  1568. onAction: () => onAction(item.value),
  1569. onSetup: onSetupToggle(editor, format, item.value)
  1570. };
  1571. }
  1572. });
  1573. const applyTableCellStyle = (editor, style) => value => {
  1574. editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });
  1575. };
  1576. const filterNoneItem = list => bind(list, item => {
  1577. if (isListGroup(item)) {
  1578. return [{
  1579. ...item,
  1580. menu: filterNoneItem(item.menu)
  1581. }];
  1582. } else {
  1583. return isNotEmpty(item.value) ? [item] : [];
  1584. }
  1585. });
  1586. const generateMenuItemsCallback = (editor, items, format, onAction) => callback => callback(buildMenuItems(editor, items, format, onAction));
  1587. const buildColorMenu = (editor, colorList, style) => {
  1588. const colorMap = map(colorList, entry => ({
  1589. text: entry.title,
  1590. value: '#' + anyToHex(entry.value).value,
  1591. type: 'choiceitem'
  1592. }));
  1593. return [{
  1594. type: 'fancymenuitem',
  1595. fancytype: 'colorswatch',
  1596. initData: {
  1597. colors: colorMap.length > 0 ? colorMap : undefined,
  1598. allowCustomColors: false
  1599. },
  1600. onAction: data => {
  1601. const value = data.value === 'remove' ? '' : data.value;
  1602. editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });
  1603. }
  1604. }];
  1605. };
  1606. const changeRowHeader = editor => () => {
  1607. const currentType = editor.queryCommandValue('mceTableRowType');
  1608. const newType = currentType === 'header' ? 'body' : 'header';
  1609. editor.execCommand('mceTableRowType', false, { type: newType });
  1610. };
  1611. const changeColumnHeader = editor => () => {
  1612. const currentType = editor.queryCommandValue('mceTableColType');
  1613. const newType = currentType === 'th' ? 'td' : 'th';
  1614. editor.execCommand('mceTableColType', false, { type: newType });
  1615. };
  1616. const getClassList$1 = editor => {
  1617. const classes = buildListItems(getCellClassList(editor));
  1618. if (classes.length > 0) {
  1619. return Optional.some({
  1620. name: 'class',
  1621. type: 'listbox',
  1622. label: 'Class',
  1623. items: classes
  1624. });
  1625. }
  1626. return Optional.none();
  1627. };
  1628. const children = [
  1629. {
  1630. name: 'width',
  1631. type: 'input',
  1632. label: 'Width'
  1633. },
  1634. {
  1635. name: 'height',
  1636. type: 'input',
  1637. label: 'Height'
  1638. },
  1639. {
  1640. name: 'celltype',
  1641. type: 'listbox',
  1642. label: 'Cell type',
  1643. items: [
  1644. {
  1645. text: 'Cell',
  1646. value: 'td'
  1647. },
  1648. {
  1649. text: 'Header cell',
  1650. value: 'th'
  1651. }
  1652. ]
  1653. },
  1654. {
  1655. name: 'scope',
  1656. type: 'listbox',
  1657. label: 'Scope',
  1658. items: [
  1659. {
  1660. text: 'None',
  1661. value: ''
  1662. },
  1663. {
  1664. text: 'Row',
  1665. value: 'row'
  1666. },
  1667. {
  1668. text: 'Column',
  1669. value: 'col'
  1670. },
  1671. {
  1672. text: 'Row group',
  1673. value: 'rowgroup'
  1674. },
  1675. {
  1676. text: 'Column group',
  1677. value: 'colgroup'
  1678. }
  1679. ]
  1680. },
  1681. {
  1682. name: 'halign',
  1683. type: 'listbox',
  1684. label: 'Horizontal align',
  1685. items: [
  1686. {
  1687. text: 'None',
  1688. value: ''
  1689. },
  1690. {
  1691. text: 'Left',
  1692. value: 'left'
  1693. },
  1694. {
  1695. text: 'Center',
  1696. value: 'center'
  1697. },
  1698. {
  1699. text: 'Right',
  1700. value: 'right'
  1701. }
  1702. ]
  1703. },
  1704. {
  1705. name: 'valign',
  1706. type: 'listbox',
  1707. label: 'Vertical align',
  1708. items: verticalAlignValues
  1709. }
  1710. ];
  1711. const getItems$2 = editor => children.concat(getClassList$1(editor).toArray());
  1712. const getAdvancedTab = (editor, dialogName) => {
  1713. const emptyBorderStyle = [{
  1714. text: 'Select...',
  1715. value: ''
  1716. }];
  1717. const advTabItems = [
  1718. {
  1719. name: 'borderstyle',
  1720. type: 'listbox',
  1721. label: 'Border style',
  1722. items: emptyBorderStyle.concat(buildListItems(getTableBorderStyles(editor)))
  1723. },
  1724. {
  1725. name: 'bordercolor',
  1726. type: 'colorinput',
  1727. label: 'Border color'
  1728. },
  1729. {
  1730. name: 'backgroundcolor',
  1731. type: 'colorinput',
  1732. label: 'Background color'
  1733. }
  1734. ];
  1735. const borderWidth = {
  1736. name: 'borderwidth',
  1737. type: 'input',
  1738. label: 'Border width'
  1739. };
  1740. const items = dialogName === 'cell' ? [borderWidth].concat(advTabItems) : advTabItems;
  1741. return {
  1742. title: 'Advanced',
  1743. name: 'advanced',
  1744. items
  1745. };
  1746. };
  1747. const normal = (editor, element) => {
  1748. const dom = editor.dom;
  1749. const setAttrib = (attr, value) => {
  1750. dom.setAttrib(element, attr, value);
  1751. };
  1752. const setStyle = (prop, value) => {
  1753. dom.setStyle(element, prop, value);
  1754. };
  1755. const setFormat = (formatName, value) => {
  1756. if (value === '') {
  1757. editor.formatter.remove(formatName, { value: null }, element, true);
  1758. } else {
  1759. editor.formatter.apply(formatName, { value }, element);
  1760. }
  1761. };
  1762. return {
  1763. setAttrib,
  1764. setStyle,
  1765. setFormat
  1766. };
  1767. };
  1768. const DomModifier = { normal };
  1769. const isHeaderCell = isTag('th');
  1770. const getRowHeaderType = (isHeaderRow, isHeaderCells) => {
  1771. if (isHeaderRow && isHeaderCells) {
  1772. return 'sectionCells';
  1773. } else if (isHeaderRow) {
  1774. return 'section';
  1775. } else {
  1776. return 'cells';
  1777. }
  1778. };
  1779. const getRowType$1 = row => {
  1780. const isHeaderRow = row.section === 'thead';
  1781. const isHeaderCells = is(findCommonCellType(row.cells), 'th');
  1782. if (row.section === 'tfoot') {
  1783. return { type: 'footer' };
  1784. } else if (isHeaderRow || isHeaderCells) {
  1785. return {
  1786. type: 'header',
  1787. subType: getRowHeaderType(isHeaderRow, isHeaderCells)
  1788. };
  1789. } else {
  1790. return { type: 'body' };
  1791. }
  1792. };
  1793. const findCommonCellType = cells => {
  1794. const headerCells = filter(cells, cell => isHeaderCell(cell.element));
  1795. if (headerCells.length === 0) {
  1796. return Optional.some('td');
  1797. } else if (headerCells.length === cells.length) {
  1798. return Optional.some('th');
  1799. } else {
  1800. return Optional.none();
  1801. }
  1802. };
  1803. const findCommonRowType = rows => {
  1804. const rowTypes = map(rows, row => getRowType$1(row).type);
  1805. const hasHeader = contains(rowTypes, 'header');
  1806. const hasFooter = contains(rowTypes, 'footer');
  1807. if (!hasHeader && !hasFooter) {
  1808. return Optional.some('body');
  1809. } else {
  1810. const hasBody = contains(rowTypes, 'body');
  1811. if (hasHeader && !hasBody && !hasFooter) {
  1812. return Optional.some('header');
  1813. } else if (!hasHeader && !hasBody && hasFooter) {
  1814. return Optional.some('footer');
  1815. } else {
  1816. return Optional.none();
  1817. }
  1818. }
  1819. };
  1820. const cached = f => {
  1821. let called = false;
  1822. let r;
  1823. return (...args) => {
  1824. if (!called) {
  1825. called = true;
  1826. r = f.apply(null, args);
  1827. }
  1828. return r;
  1829. };
  1830. };
  1831. const findInWarehouse = (warehouse, element) => findMap(warehouse.all, r => find(r.cells, e => eq(element, e.element)));
  1832. const extractCells = (warehouse, target, predicate) => {
  1833. const details = map(target.selection, cell$1 => {
  1834. return cell(cell$1).bind(lc => findInWarehouse(warehouse, lc)).filter(predicate);
  1835. });
  1836. const cells = cat(details);
  1837. return someIf(cells.length > 0, cells);
  1838. };
  1839. const onMergable = (_warehouse, target) => target.mergable;
  1840. const onUnmergable = (_warehouse, target) => target.unmergable;
  1841. const onCells = (warehouse, target) => extractCells(warehouse, target, always);
  1842. const isUnlockedTableCell = (warehouse, cell) => findInWarehouse(warehouse, cell).exists(detail => !detail.isLocked);
  1843. const allUnlocked = (warehouse, cells) => forall(cells, cell => isUnlockedTableCell(warehouse, cell));
  1844. const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter(mergeable => allUnlocked(warehouse, mergeable.cells));
  1845. const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter(cells => allUnlocked(warehouse, cells));
  1846. const generate = cases => {
  1847. if (!isArray(cases)) {
  1848. throw new Error('cases must be an array');
  1849. }
  1850. if (cases.length === 0) {
  1851. throw new Error('there must be at least one case');
  1852. }
  1853. const constructors = [];
  1854. const adt = {};
  1855. each(cases, (acase, count) => {
  1856. const keys$1 = keys(acase);
  1857. if (keys$1.length !== 1) {
  1858. throw new Error('one and only one name per case');
  1859. }
  1860. const key = keys$1[0];
  1861. const value = acase[key];
  1862. if (adt[key] !== undefined) {
  1863. throw new Error('duplicate key detected:' + key);
  1864. } else if (key === 'cata') {
  1865. throw new Error('cannot have a case named cata (sorry)');
  1866. } else if (!isArray(value)) {
  1867. throw new Error('case arguments must be an array');
  1868. }
  1869. constructors.push(key);
  1870. adt[key] = (...args) => {
  1871. const argLength = args.length;
  1872. if (argLength !== value.length) {
  1873. throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);
  1874. }
  1875. const match = branches => {
  1876. const branchKeys = keys(branches);
  1877. if (constructors.length !== branchKeys.length) {
  1878. throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\nActual: ' + branchKeys.join(','));
  1879. }
  1880. const allReqd = forall(constructors, reqKey => {
  1881. return contains(branchKeys, reqKey);
  1882. });
  1883. if (!allReqd) {
  1884. throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\nRequired: ' + constructors.join(', '));
  1885. }
  1886. return branches[key].apply(null, args);
  1887. };
  1888. return {
  1889. fold: (...foldArgs) => {
  1890. if (foldArgs.length !== cases.length) {
  1891. throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);
  1892. }
  1893. const target = foldArgs[count];
  1894. return target.apply(null, args);
  1895. },
  1896. match,
  1897. log: label => {
  1898. console.log(label, {
  1899. constructors,
  1900. constructor: key,
  1901. params: args
  1902. });
  1903. }
  1904. };
  1905. };
  1906. });
  1907. return adt;
  1908. };
  1909. const Adt = { generate };
  1910. const adt = Adt.generate([
  1911. { none: [] },
  1912. { only: ['index'] },
  1913. {
  1914. left: [
  1915. 'index',
  1916. 'next'
  1917. ]
  1918. },
  1919. {
  1920. middle: [
  1921. 'prev',
  1922. 'index',
  1923. 'next'
  1924. ]
  1925. },
  1926. {
  1927. right: [
  1928. 'prev',
  1929. 'index'
  1930. ]
  1931. }
  1932. ]);
  1933. ({ ...adt });
  1934. const opGetRowsType = (table, target) => {
  1935. const house = Warehouse.fromTable(table);
  1936. const details = onCells(house, target);
  1937. return details.bind(selectedCells => {
  1938. const lastSelectedCell = selectedCells[selectedCells.length - 1];
  1939. const minRowRange = selectedCells[0].row;
  1940. const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan;
  1941. const selectedRows = house.all.slice(minRowRange, maxRowRange);
  1942. return findCommonRowType(selectedRows);
  1943. }).getOr('');
  1944. };
  1945. const getRowsType = opGetRowsType;
  1946. const rgbToHex = value => startsWith(value, 'rgb') ? rgbaToHexString(value) : value;
  1947. const extractAdvancedStyles = elm => {
  1948. const element = SugarElement.fromDom(elm);
  1949. return {
  1950. borderwidth: getRaw(element, 'border-width').getOr(''),
  1951. borderstyle: getRaw(element, 'border-style').getOr(''),
  1952. bordercolor: getRaw(element, 'border-color').map(rgbToHex).getOr(''),
  1953. backgroundcolor: getRaw(element, 'background-color').map(rgbToHex).getOr('')
  1954. };
  1955. };
  1956. const getSharedValues = data => {
  1957. const baseData = data[0];
  1958. const comparisonData = data.slice(1);
  1959. each(comparisonData, items => {
  1960. each(keys(baseData), key => {
  1961. each$1(items, (itemValue, itemKey) => {
  1962. const comparisonValue = baseData[key];
  1963. if (comparisonValue !== '' && key === itemKey) {
  1964. if (comparisonValue !== itemValue) {
  1965. baseData[key] = '';
  1966. }
  1967. }
  1968. });
  1969. });
  1970. });
  1971. return baseData;
  1972. };
  1973. const getAlignment = (formats, formatName, editor, elm) => find(formats, name => !isUndefined(editor.formatter.matchNode(elm, formatName + name))).getOr('');
  1974. const getHAlignment = curry(getAlignment, [
  1975. 'left',
  1976. 'center',
  1977. 'right'
  1978. ], 'align');
  1979. const getVAlignment = curry(getAlignment, [
  1980. 'top',
  1981. 'middle',
  1982. 'bottom'
  1983. ], 'valign');
  1984. const extractDataFromSettings = (editor, hasAdvTableTab) => {
  1985. const style = getDefaultStyles(editor);
  1986. const attrs = getDefaultAttributes(editor);
  1987. const extractAdvancedStyleData = () => ({
  1988. borderstyle: get$4(style, 'border-style').getOr(''),
  1989. bordercolor: rgbToHex(get$4(style, 'border-color').getOr('')),
  1990. backgroundcolor: rgbToHex(get$4(style, 'background-color').getOr(''))
  1991. });
  1992. const defaultData = {
  1993. height: '',
  1994. width: '100%',
  1995. cellspacing: '',
  1996. cellpadding: '',
  1997. caption: false,
  1998. class: '',
  1999. align: '',
  2000. border: ''
  2001. };
  2002. const getBorder = () => {
  2003. const borderWidth = style['border-width'];
  2004. if (shouldStyleWithCss(editor) && borderWidth) {
  2005. return { border: borderWidth };
  2006. }
  2007. return get$4(attrs, 'border').fold(() => ({}), border => ({ border }));
  2008. };
  2009. const advStyle = hasAdvTableTab ? extractAdvancedStyleData() : {};
  2010. const getCellPaddingCellSpacing = () => {
  2011. const spacing = get$4(style, 'border-spacing').or(get$4(attrs, 'cellspacing')).fold(() => ({}), cellspacing => ({ cellspacing }));
  2012. const padding = get$4(style, 'border-padding').or(get$4(attrs, 'cellpadding')).fold(() => ({}), cellpadding => ({ cellpadding }));
  2013. return {
  2014. ...spacing,
  2015. ...padding
  2016. };
  2017. };
  2018. const data = {
  2019. ...defaultData,
  2020. ...style,
  2021. ...attrs,
  2022. ...advStyle,
  2023. ...getBorder(),
  2024. ...getCellPaddingCellSpacing()
  2025. };
  2026. return data;
  2027. };
  2028. const getRowType = elm => table(SugarElement.fromDom(elm)).map(table => {
  2029. const target = { selection: fromDom(elm.cells) };
  2030. return getRowsType(table, target);
  2031. }).getOr('');
  2032. const extractDataFromTableElement = (editor, elm, hasAdvTableTab) => {
  2033. const getBorder = (dom, elm) => {
  2034. const optBorderWidth = getRaw(SugarElement.fromDom(elm), 'border-width');
  2035. if (shouldStyleWithCss(editor) && optBorderWidth.isSome()) {
  2036. return optBorderWidth.getOr('');
  2037. }
  2038. return dom.getAttrib(elm, 'border') || getTDTHOverallStyle(editor.dom, elm, 'border-width') || getTDTHOverallStyle(editor.dom, elm, 'border') || '';
  2039. };
  2040. const dom = editor.dom;
  2041. const cellspacing = shouldStyleWithCss(editor) ? dom.getStyle(elm, 'border-spacing') || dom.getAttrib(elm, 'cellspacing') : dom.getAttrib(elm, 'cellspacing') || dom.getStyle(elm, 'border-spacing');
  2042. const cellpadding = shouldStyleWithCss(editor) ? getTDTHOverallStyle(dom, elm, 'padding') || dom.getAttrib(elm, 'cellpadding') : dom.getAttrib(elm, 'cellpadding') || getTDTHOverallStyle(dom, elm, 'padding');
  2043. return {
  2044. width: dom.getStyle(elm, 'width') || dom.getAttrib(elm, 'width'),
  2045. height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),
  2046. cellspacing: cellspacing !== null && cellspacing !== void 0 ? cellspacing : '',
  2047. cellpadding: cellpadding !== null && cellpadding !== void 0 ? cellpadding : '',
  2048. border: getBorder(dom, elm),
  2049. caption: !!dom.select('caption', elm)[0],
  2050. class: dom.getAttrib(elm, 'class', ''),
  2051. align: getHAlignment(editor, elm),
  2052. ...hasAdvTableTab ? extractAdvancedStyles(elm) : {}
  2053. };
  2054. };
  2055. const extractDataFromRowElement = (editor, elm, hasAdvancedRowTab) => {
  2056. const dom = editor.dom;
  2057. return {
  2058. height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),
  2059. class: dom.getAttrib(elm, 'class', ''),
  2060. type: getRowType(elm),
  2061. align: getHAlignment(editor, elm),
  2062. ...hasAdvancedRowTab ? extractAdvancedStyles(elm) : {}
  2063. };
  2064. };
  2065. const extractDataFromCellElement = (editor, cell, hasAdvancedCellTab, column) => {
  2066. const dom = editor.dom;
  2067. const colElm = column.getOr(cell);
  2068. const getStyle = (element, style) => dom.getStyle(element, style) || dom.getAttrib(element, style);
  2069. return {
  2070. width: getStyle(colElm, 'width'),
  2071. height: getStyle(cell, 'height'),
  2072. scope: dom.getAttrib(cell, 'scope'),
  2073. celltype: getNodeName(cell),
  2074. class: dom.getAttrib(cell, 'class', ''),
  2075. halign: getHAlignment(editor, cell),
  2076. valign: getVAlignment(editor, cell),
  2077. ...hasAdvancedCellTab ? extractAdvancedStyles(cell) : {}
  2078. };
  2079. };
  2080. const getSelectedCells = (table, cells) => {
  2081. const warehouse = Warehouse.fromTable(table);
  2082. const allCells = Warehouse.justCells(warehouse);
  2083. const filtered = filter(allCells, cellA => exists(cells, cellB => eq(cellA.element, cellB)));
  2084. return map(filtered, cell => ({
  2085. element: cell.element.dom,
  2086. column: Warehouse.getColumnAt(warehouse, cell.column).map(col => col.element.dom)
  2087. }));
  2088. };
  2089. const updateSimpleProps$1 = (modifier, colModifier, data, shouldUpdate) => {
  2090. if (shouldUpdate('scope')) {
  2091. modifier.setAttrib('scope', data.scope);
  2092. }
  2093. if (shouldUpdate('class')) {
  2094. modifier.setAttrib('class', data.class);
  2095. }
  2096. if (shouldUpdate('height')) {
  2097. modifier.setStyle('height', addPxSuffix(data.height));
  2098. }
  2099. if (shouldUpdate('width')) {
  2100. colModifier.setStyle('width', addPxSuffix(data.width));
  2101. }
  2102. };
  2103. const updateAdvancedProps$1 = (modifier, data, shouldUpdate) => {
  2104. if (shouldUpdate('backgroundcolor')) {
  2105. modifier.setFormat('tablecellbackgroundcolor', data.backgroundcolor);
  2106. }
  2107. if (shouldUpdate('bordercolor')) {
  2108. modifier.setFormat('tablecellbordercolor', data.bordercolor);
  2109. }
  2110. if (shouldUpdate('borderstyle')) {
  2111. modifier.setFormat('tablecellborderstyle', data.borderstyle);
  2112. }
  2113. if (shouldUpdate('borderwidth')) {
  2114. modifier.setFormat('tablecellborderwidth', addPxSuffix(data.borderwidth));
  2115. }
  2116. };
  2117. const applyStyleData$1 = (editor, cells, data, wasChanged) => {
  2118. const isSingleCell = cells.length === 1;
  2119. each(cells, item => {
  2120. const cellElm = item.element;
  2121. const shouldOverrideCurrentValue = isSingleCell ? always : wasChanged;
  2122. const modifier = DomModifier.normal(editor, cellElm);
  2123. const colModifier = item.column.map(col => DomModifier.normal(editor, col)).getOr(modifier);
  2124. updateSimpleProps$1(modifier, colModifier, data, shouldOverrideCurrentValue);
  2125. if (hasAdvancedCellTab(editor)) {
  2126. updateAdvancedProps$1(modifier, data, shouldOverrideCurrentValue);
  2127. }
  2128. if (wasChanged('halign')) {
  2129. setAlign(editor, cellElm, data.halign);
  2130. }
  2131. if (wasChanged('valign')) {
  2132. setVAlign(editor, cellElm, data.valign);
  2133. }
  2134. });
  2135. };
  2136. const applyStructureData$1 = (editor, data) => {
  2137. editor.execCommand('mceTableCellType', false, {
  2138. type: data.celltype,
  2139. no_events: true
  2140. });
  2141. };
  2142. const applyCellData = (editor, cells, oldData, data) => {
  2143. const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
  2144. if (size(modifiedData) > 0 && cells.length >= 1) {
  2145. table(cells[0]).each(table => {
  2146. const selectedCells = getSelectedCells(table, cells);
  2147. const styleModified = size(filter$1(modifiedData, (_value, key) => key !== 'scope' && key !== 'celltype')) > 0;
  2148. const structureModified = has(modifiedData, 'celltype');
  2149. if (styleModified || has(modifiedData, 'scope')) {
  2150. applyStyleData$1(editor, selectedCells, data, curry(has, modifiedData));
  2151. }
  2152. if (structureModified) {
  2153. applyStructureData$1(editor, data);
  2154. }
  2155. fireTableModified(editor, table.dom, {
  2156. structure: structureModified,
  2157. style: styleModified
  2158. });
  2159. });
  2160. }
  2161. };
  2162. const onSubmitCellForm = (editor, cells, oldData, api) => {
  2163. const data = api.getData();
  2164. api.close();
  2165. editor.undoManager.transact(() => {
  2166. applyCellData(editor, cells, oldData, data);
  2167. editor.focus();
  2168. });
  2169. };
  2170. const getData$1 = (editor, cells) => {
  2171. const cellsData = table(cells[0]).map(table => map(getSelectedCells(table, cells), item => extractDataFromCellElement(editor, item.element, hasAdvancedCellTab(editor), item.column)));
  2172. return getSharedValues(cellsData.getOrDie());
  2173. };
  2174. const open$2 = editor => {
  2175. const cells = getCellsFromSelection(editor);
  2176. if (cells.length === 0) {
  2177. return;
  2178. }
  2179. const data = getData$1(editor, cells);
  2180. const dialogTabPanel = {
  2181. type: 'tabpanel',
  2182. tabs: [
  2183. {
  2184. title: 'General',
  2185. name: 'general',
  2186. items: getItems$2(editor)
  2187. },
  2188. getAdvancedTab(editor, 'cell')
  2189. ]
  2190. };
  2191. const dialogPanel = {
  2192. type: 'panel',
  2193. items: [{
  2194. type: 'grid',
  2195. columns: 2,
  2196. items: getItems$2(editor)
  2197. }]
  2198. };
  2199. editor.windowManager.open({
  2200. title: 'Cell Properties',
  2201. size: 'normal',
  2202. body: hasAdvancedCellTab(editor) ? dialogTabPanel : dialogPanel,
  2203. buttons: [
  2204. {
  2205. type: 'cancel',
  2206. name: 'cancel',
  2207. text: 'Cancel'
  2208. },
  2209. {
  2210. type: 'submit',
  2211. name: 'save',
  2212. text: 'Save',
  2213. primary: true
  2214. }
  2215. ],
  2216. initialData: data,
  2217. onSubmit: curry(onSubmitCellForm, editor, cells, data)
  2218. });
  2219. };
  2220. const getClassList = editor => {
  2221. const classes = buildListItems(getRowClassList(editor));
  2222. if (classes.length > 0) {
  2223. return Optional.some({
  2224. name: 'class',
  2225. type: 'listbox',
  2226. label: 'Class',
  2227. items: classes
  2228. });
  2229. }
  2230. return Optional.none();
  2231. };
  2232. const formChildren = [
  2233. {
  2234. type: 'listbox',
  2235. name: 'type',
  2236. label: 'Row type',
  2237. items: [
  2238. {
  2239. text: 'Header',
  2240. value: 'header'
  2241. },
  2242. {
  2243. text: 'Body',
  2244. value: 'body'
  2245. },
  2246. {
  2247. text: 'Footer',
  2248. value: 'footer'
  2249. }
  2250. ]
  2251. },
  2252. {
  2253. type: 'listbox',
  2254. name: 'align',
  2255. label: 'Alignment',
  2256. items: [
  2257. {
  2258. text: 'None',
  2259. value: ''
  2260. },
  2261. {
  2262. text: 'Left',
  2263. value: 'left'
  2264. },
  2265. {
  2266. text: 'Center',
  2267. value: 'center'
  2268. },
  2269. {
  2270. text: 'Right',
  2271. value: 'right'
  2272. }
  2273. ]
  2274. },
  2275. {
  2276. label: 'Height',
  2277. name: 'height',
  2278. type: 'input'
  2279. }
  2280. ];
  2281. const getItems$1 = editor => formChildren.concat(getClassList(editor).toArray());
  2282. const updateSimpleProps = (modifier, data, shouldUpdate) => {
  2283. if (shouldUpdate('class')) {
  2284. modifier.setAttrib('class', data.class);
  2285. }
  2286. if (shouldUpdate('height')) {
  2287. modifier.setStyle('height', addPxSuffix(data.height));
  2288. }
  2289. };
  2290. const updateAdvancedProps = (modifier, data, shouldUpdate) => {
  2291. if (shouldUpdate('backgroundcolor')) {
  2292. modifier.setStyle('background-color', data.backgroundcolor);
  2293. }
  2294. if (shouldUpdate('bordercolor')) {
  2295. modifier.setStyle('border-color', data.bordercolor);
  2296. }
  2297. if (shouldUpdate('borderstyle')) {
  2298. modifier.setStyle('border-style', data.borderstyle);
  2299. }
  2300. };
  2301. const applyStyleData = (editor, rows, data, wasChanged) => {
  2302. const isSingleRow = rows.length === 1;
  2303. const shouldOverrideCurrentValue = isSingleRow ? always : wasChanged;
  2304. each(rows, rowElm => {
  2305. const modifier = DomModifier.normal(editor, rowElm);
  2306. updateSimpleProps(modifier, data, shouldOverrideCurrentValue);
  2307. if (hasAdvancedRowTab(editor)) {
  2308. updateAdvancedProps(modifier, data, shouldOverrideCurrentValue);
  2309. }
  2310. if (wasChanged('align')) {
  2311. setAlign(editor, rowElm, data.align);
  2312. }
  2313. });
  2314. };
  2315. const applyStructureData = (editor, data) => {
  2316. editor.execCommand('mceTableRowType', false, {
  2317. type: data.type,
  2318. no_events: true
  2319. });
  2320. };
  2321. const applyRowData = (editor, rows, oldData, data) => {
  2322. const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
  2323. if (size(modifiedData) > 0) {
  2324. const typeModified = has(modifiedData, 'type');
  2325. const styleModified = typeModified ? size(modifiedData) > 1 : true;
  2326. if (styleModified) {
  2327. applyStyleData(editor, rows, data, curry(has, modifiedData));
  2328. }
  2329. if (typeModified) {
  2330. applyStructureData(editor, data);
  2331. }
  2332. table(SugarElement.fromDom(rows[0])).each(table => fireTableModified(editor, table.dom, {
  2333. structure: typeModified,
  2334. style: styleModified
  2335. }));
  2336. }
  2337. };
  2338. const onSubmitRowForm = (editor, rows, oldData, api) => {
  2339. const data = api.getData();
  2340. api.close();
  2341. editor.undoManager.transact(() => {
  2342. applyRowData(editor, rows, oldData, data);
  2343. editor.focus();
  2344. });
  2345. };
  2346. const open$1 = editor => {
  2347. const rows = getRowsFromSelection(getSelectionStart(editor), ephemera.selected);
  2348. if (rows.length === 0) {
  2349. return;
  2350. }
  2351. const rowsData = map(rows, rowElm => extractDataFromRowElement(editor, rowElm.dom, hasAdvancedRowTab(editor)));
  2352. const data = getSharedValues(rowsData);
  2353. const dialogTabPanel = {
  2354. type: 'tabpanel',
  2355. tabs: [
  2356. {
  2357. title: 'General',
  2358. name: 'general',
  2359. items: getItems$1(editor)
  2360. },
  2361. getAdvancedTab(editor, 'row')
  2362. ]
  2363. };
  2364. const dialogPanel = {
  2365. type: 'panel',
  2366. items: [{
  2367. type: 'grid',
  2368. columns: 2,
  2369. items: getItems$1(editor)
  2370. }]
  2371. };
  2372. editor.windowManager.open({
  2373. title: 'Row Properties',
  2374. size: 'normal',
  2375. body: hasAdvancedRowTab(editor) ? dialogTabPanel : dialogPanel,
  2376. buttons: [
  2377. {
  2378. type: 'cancel',
  2379. name: 'cancel',
  2380. text: 'Cancel'
  2381. },
  2382. {
  2383. type: 'submit',
  2384. name: 'save',
  2385. text: 'Save',
  2386. primary: true
  2387. }
  2388. ],
  2389. initialData: data,
  2390. onSubmit: curry(onSubmitRowForm, editor, map(rows, r => r.dom), data)
  2391. });
  2392. };
  2393. const getItems = (editor, classes, insertNewTable) => {
  2394. const rowColCountItems = !insertNewTable ? [] : [
  2395. {
  2396. type: 'input',
  2397. name: 'cols',
  2398. label: 'Cols',
  2399. inputMode: 'numeric'
  2400. },
  2401. {
  2402. type: 'input',
  2403. name: 'rows',
  2404. label: 'Rows',
  2405. inputMode: 'numeric'
  2406. }
  2407. ];
  2408. const alwaysItems = [
  2409. {
  2410. type: 'input',
  2411. name: 'width',
  2412. label: 'Width'
  2413. },
  2414. {
  2415. type: 'input',
  2416. name: 'height',
  2417. label: 'Height'
  2418. }
  2419. ];
  2420. const appearanceItems = hasAppearanceOptions(editor) ? [
  2421. {
  2422. type: 'input',
  2423. name: 'cellspacing',
  2424. label: 'Cell spacing',
  2425. inputMode: 'numeric'
  2426. },
  2427. {
  2428. type: 'input',
  2429. name: 'cellpadding',
  2430. label: 'Cell padding',
  2431. inputMode: 'numeric'
  2432. },
  2433. {
  2434. type: 'input',
  2435. name: 'border',
  2436. label: 'Border width'
  2437. },
  2438. {
  2439. type: 'label',
  2440. label: 'Caption',
  2441. items: [{
  2442. type: 'checkbox',
  2443. name: 'caption',
  2444. label: 'Show caption'
  2445. }]
  2446. }
  2447. ] : [];
  2448. const alignmentItem = [{
  2449. type: 'listbox',
  2450. name: 'align',
  2451. label: 'Alignment',
  2452. items: [
  2453. {
  2454. text: 'None',
  2455. value: ''
  2456. },
  2457. {
  2458. text: 'Left',
  2459. value: 'left'
  2460. },
  2461. {
  2462. text: 'Center',
  2463. value: 'center'
  2464. },
  2465. {
  2466. text: 'Right',
  2467. value: 'right'
  2468. }
  2469. ]
  2470. }];
  2471. const classListItem = classes.length > 0 ? [{
  2472. type: 'listbox',
  2473. name: 'class',
  2474. label: 'Class',
  2475. items: classes
  2476. }] : [];
  2477. return rowColCountItems.concat(alwaysItems).concat(appearanceItems).concat(alignmentItem).concat(classListItem);
  2478. };
  2479. const styleTDTH = (dom, elm, name, value) => {
  2480. if (elm.tagName === 'TD' || elm.tagName === 'TH') {
  2481. if (isString(name) && isNonNullable(value)) {
  2482. dom.setStyle(elm, name, value);
  2483. } else {
  2484. dom.setStyles(elm, name);
  2485. }
  2486. } else {
  2487. if (elm.children) {
  2488. for (let i = 0; i < elm.children.length; i++) {
  2489. styleTDTH(dom, elm.children[i], name, value);
  2490. }
  2491. }
  2492. }
  2493. };
  2494. const applyDataToElement = (editor, tableElm, data, shouldApplyOnCell) => {
  2495. const dom = editor.dom;
  2496. const attrs = {};
  2497. const styles = {};
  2498. const shouldStyleWithCss$1 = shouldStyleWithCss(editor);
  2499. const hasAdvancedTableTab$1 = hasAdvancedTableTab(editor);
  2500. if (!isUndefined(data.class)) {
  2501. attrs.class = data.class;
  2502. }
  2503. styles.height = addPxSuffix(data.height);
  2504. if (shouldStyleWithCss$1) {
  2505. styles.width = addPxSuffix(data.width);
  2506. } else if (dom.getAttrib(tableElm, 'width')) {
  2507. attrs.width = removePxSuffix(data.width);
  2508. }
  2509. if (shouldStyleWithCss$1) {
  2510. styles['border-width'] = addPxSuffix(data.border);
  2511. styles['border-spacing'] = addPxSuffix(data.cellspacing);
  2512. } else {
  2513. attrs.border = data.border;
  2514. attrs.cellpadding = data.cellpadding;
  2515. attrs.cellspacing = data.cellspacing;
  2516. }
  2517. if (shouldStyleWithCss$1 && tableElm.children) {
  2518. const cellStyles = {};
  2519. if (shouldApplyOnCell.border) {
  2520. cellStyles['border-width'] = addPxSuffix(data.border);
  2521. }
  2522. if (shouldApplyOnCell.cellpadding) {
  2523. cellStyles.padding = addPxSuffix(data.cellpadding);
  2524. }
  2525. if (hasAdvancedTableTab$1 && shouldApplyOnCell.bordercolor) {
  2526. cellStyles['border-color'] = data.bordercolor;
  2527. }
  2528. if (!isEmpty$1(cellStyles)) {
  2529. for (let i = 0; i < tableElm.children.length; i++) {
  2530. styleTDTH(dom, tableElm.children[i], cellStyles);
  2531. }
  2532. }
  2533. }
  2534. if (hasAdvancedTableTab$1) {
  2535. const advData = data;
  2536. styles['background-color'] = advData.backgroundcolor;
  2537. styles['border-color'] = advData.bordercolor;
  2538. styles['border-style'] = advData.borderstyle;
  2539. }
  2540. dom.setStyles(tableElm, {
  2541. ...getDefaultStyles(editor),
  2542. ...styles
  2543. });
  2544. dom.setAttribs(tableElm, {
  2545. ...getDefaultAttributes(editor),
  2546. ...attrs
  2547. });
  2548. };
  2549. const onSubmitTableForm = (editor, tableElm, oldData, api) => {
  2550. const dom = editor.dom;
  2551. const data = api.getData();
  2552. const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);
  2553. api.close();
  2554. if (data.class === '') {
  2555. delete data.class;
  2556. }
  2557. editor.undoManager.transact(() => {
  2558. if (!tableElm) {
  2559. const cols = toInt(data.cols).getOr(1);
  2560. const rows = toInt(data.rows).getOr(1);
  2561. editor.execCommand('mceInsertTable', false, {
  2562. rows,
  2563. columns: cols
  2564. });
  2565. tableElm = getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).bind(cell => table(cell, getIsRoot(editor))).map(table => table.dom).getOrDie();
  2566. }
  2567. if (size(modifiedData) > 0) {
  2568. const applicableCellProperties = {
  2569. border: has(modifiedData, 'border'),
  2570. bordercolor: has(modifiedData, 'bordercolor'),
  2571. cellpadding: has(modifiedData, 'cellpadding')
  2572. };
  2573. applyDataToElement(editor, tableElm, data, applicableCellProperties);
  2574. const captionElm = dom.select('caption', tableElm)[0];
  2575. if (captionElm && !data.caption || !captionElm && data.caption) {
  2576. editor.execCommand('mceTableToggleCaption');
  2577. }
  2578. setAlign(editor, tableElm, data.align);
  2579. }
  2580. editor.focus();
  2581. editor.addVisual();
  2582. if (size(modifiedData) > 0) {
  2583. const captionModified = has(modifiedData, 'caption');
  2584. const styleModified = captionModified ? size(modifiedData) > 1 : true;
  2585. fireTableModified(editor, tableElm, {
  2586. structure: captionModified,
  2587. style: styleModified
  2588. });
  2589. }
  2590. });
  2591. };
  2592. const open = (editor, insertNewTable) => {
  2593. const dom = editor.dom;
  2594. let tableElm;
  2595. let data = extractDataFromSettings(editor, hasAdvancedTableTab(editor));
  2596. if (insertNewTable) {
  2597. data.cols = '1';
  2598. data.rows = '1';
  2599. if (hasAdvancedTableTab(editor)) {
  2600. data.borderstyle = '';
  2601. data.bordercolor = '';
  2602. data.backgroundcolor = '';
  2603. }
  2604. } else {
  2605. tableElm = dom.getParent(editor.selection.getStart(), 'table', editor.getBody());
  2606. if (tableElm) {
  2607. data = extractDataFromTableElement(editor, tableElm, hasAdvancedTableTab(editor));
  2608. } else {
  2609. if (hasAdvancedTableTab(editor)) {
  2610. data.borderstyle = '';
  2611. data.bordercolor = '';
  2612. data.backgroundcolor = '';
  2613. }
  2614. }
  2615. }
  2616. const classes = buildListItems(getTableClassList(editor));
  2617. if (classes.length > 0) {
  2618. if (data.class) {
  2619. data.class = data.class.replace(/\s*mce\-item\-table\s*/g, '');
  2620. }
  2621. }
  2622. const generalPanel = {
  2623. type: 'grid',
  2624. columns: 2,
  2625. items: getItems(editor, classes, insertNewTable)
  2626. };
  2627. const nonAdvancedForm = () => ({
  2628. type: 'panel',
  2629. items: [generalPanel]
  2630. });
  2631. const advancedForm = () => ({
  2632. type: 'tabpanel',
  2633. tabs: [
  2634. {
  2635. title: 'General',
  2636. name: 'general',
  2637. items: [generalPanel]
  2638. },
  2639. getAdvancedTab(editor, 'table')
  2640. ]
  2641. });
  2642. const dialogBody = hasAdvancedTableTab(editor) ? advancedForm() : nonAdvancedForm();
  2643. editor.windowManager.open({
  2644. title: 'Table Properties',
  2645. size: 'normal',
  2646. body: dialogBody,
  2647. onSubmit: curry(onSubmitTableForm, editor, tableElm, data),
  2648. buttons: [
  2649. {
  2650. type: 'cancel',
  2651. name: 'cancel',
  2652. text: 'Cancel'
  2653. },
  2654. {
  2655. type: 'submit',
  2656. name: 'save',
  2657. text: 'Save',
  2658. primary: true
  2659. }
  2660. ],
  2661. initialData: data
  2662. });
  2663. };
  2664. const registerCommands = editor => {
  2665. const runAction = f => {
  2666. if (isInEditableContext(getSelectionStart(editor))) {
  2667. f();
  2668. }
  2669. };
  2670. each$1({
  2671. mceTableProps: curry(open, editor, false),
  2672. mceTableRowProps: curry(open$1, editor),
  2673. mceTableCellProps: curry(open$2, editor),
  2674. mceInsertTableDialog: curry(open, editor, true)
  2675. }, (func, name) => editor.addCommand(name, () => runAction(func)));
  2676. };
  2677. const child = (scope, selector) => child$1(scope, selector).isSome();
  2678. const selection = identity;
  2679. const unmergable = selectedCells => {
  2680. const hasSpan = (elem, type) => getOpt(elem, type).exists(span => parseInt(span, 10) > 1);
  2681. const hasRowOrColSpan = elem => hasSpan(elem, 'rowspan') || hasSpan(elem, 'colspan');
  2682. return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none();
  2683. };
  2684. const mergable = (table, selectedCells, ephemera) => {
  2685. if (selectedCells.length <= 1) {
  2686. return Optional.none();
  2687. } else {
  2688. return retrieveBox(table, ephemera.firstSelectedSelector, ephemera.lastSelectedSelector).map(bounds => ({
  2689. bounds,
  2690. cells: selectedCells
  2691. }));
  2692. }
  2693. };
  2694. const noMenu = cell => ({
  2695. element: cell,
  2696. mergable: Optional.none(),
  2697. unmergable: Optional.none(),
  2698. selection: [cell]
  2699. });
  2700. const forMenu = (selectedCells, table, cell) => ({
  2701. element: cell,
  2702. mergable: mergable(table, selectedCells, ephemera),
  2703. unmergable: unmergable(selectedCells),
  2704. selection: selection(selectedCells)
  2705. });
  2706. const getSelectionTargets = editor => {
  2707. const targets = Cell(Optional.none());
  2708. const changeHandlers = Cell([]);
  2709. let selectionDetails = Optional.none();
  2710. const isCaption = isTag('caption');
  2711. const isDisabledForSelection = key => selectionDetails.forall(details => !details[key]);
  2712. const getStart = () => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor));
  2713. const getEnd = () => getSelectionCellOrCaption(getSelectionEnd(editor), getIsRoot(editor));
  2714. const findTargets = () => getStart().bind(startCellOrCaption => flatten(lift2(table(startCellOrCaption), getEnd().bind(table), (startTable, endTable) => {
  2715. if (eq(startTable, endTable)) {
  2716. if (isCaption(startCellOrCaption)) {
  2717. return Optional.some(noMenu(startCellOrCaption));
  2718. } else {
  2719. return Optional.some(forMenu(getCellsFromSelection(editor), startTable, startCellOrCaption));
  2720. }
  2721. }
  2722. return Optional.none();
  2723. })));
  2724. const getExtractedDetails = targets => {
  2725. const tableOpt = table(targets.element);
  2726. return tableOpt.map(table => {
  2727. const warehouse = Warehouse.fromTable(table);
  2728. const selectedCells = onCells(warehouse, targets).getOr([]);
  2729. const locked = foldl(selectedCells, (acc, cell) => {
  2730. if (cell.isLocked) {
  2731. acc.onAny = true;
  2732. if (cell.column === 0) {
  2733. acc.onFirst = true;
  2734. } else if (cell.column + cell.colspan >= warehouse.grid.columns) {
  2735. acc.onLast = true;
  2736. }
  2737. }
  2738. return acc;
  2739. }, {
  2740. onAny: false,
  2741. onFirst: false,
  2742. onLast: false
  2743. });
  2744. return {
  2745. mergeable: onUnlockedMergable(warehouse, targets).isSome(),
  2746. unmergeable: onUnlockedUnmergable(warehouse, targets).isSome(),
  2747. locked
  2748. };
  2749. });
  2750. };
  2751. const resetTargets = () => {
  2752. targets.set(cached(findTargets)());
  2753. selectionDetails = targets.get().bind(getExtractedDetails);
  2754. each(changeHandlers.get(), call);
  2755. };
  2756. const setupHandler = handler => {
  2757. handler();
  2758. changeHandlers.set(changeHandlers.get().concat([handler]));
  2759. return () => {
  2760. changeHandlers.set(filter(changeHandlers.get(), h => h !== handler));
  2761. };
  2762. };
  2763. const onSetup = (api, isDisabled) => setupHandler(() => targets.get().fold(() => {
  2764. api.setEnabled(false);
  2765. }, targets => {
  2766. api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());
  2767. }));
  2768. const onSetupWithToggle = (api, isDisabled, isActive) => setupHandler(() => targets.get().fold(() => {
  2769. api.setEnabled(false);
  2770. api.setActive(false);
  2771. }, targets => {
  2772. api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());
  2773. api.setActive(isActive(targets));
  2774. }));
  2775. const isDisabledFromLocked = lockedDisable => selectionDetails.exists(details => details.locked[lockedDisable]);
  2776. const onSetupTable = api => onSetup(api, _ => false);
  2777. const onSetupCellOrRow = api => onSetup(api, targets => isCaption(targets.element));
  2778. const onSetupColumn = lockedDisable => api => onSetup(api, targets => isCaption(targets.element) || isDisabledFromLocked(lockedDisable));
  2779. const onSetupPasteable = getClipboardData => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone());
  2780. const onSetupPasteableColumn = (getClipboardData, lockedDisable) => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone() || isDisabledFromLocked(lockedDisable));
  2781. const onSetupMergeable = api => onSetup(api, _targets => isDisabledForSelection('mergeable'));
  2782. const onSetupUnmergeable = api => onSetup(api, _targets => isDisabledForSelection('unmergeable'));
  2783. const onSetupTableWithCaption = api => {
  2784. return onSetupWithToggle(api, never, targets => {
  2785. const tableOpt = table(targets.element, getIsRoot(editor));
  2786. return tableOpt.exists(table => child(table, 'caption'));
  2787. });
  2788. };
  2789. const onSetupTableHeaders = (command, headerType) => api => {
  2790. return onSetupWithToggle(api, targets => isCaption(targets.element), () => editor.queryCommandValue(command) === headerType);
  2791. };
  2792. const onSetupTableRowHeaders = onSetupTableHeaders('mceTableRowType', 'header');
  2793. const onSetupTableColumnHeaders = onSetupTableHeaders('mceTableColType', 'th');
  2794. editor.on('NodeChange ExecCommand TableSelectorChange', resetTargets);
  2795. return {
  2796. onSetupTable,
  2797. onSetupCellOrRow,
  2798. onSetupColumn,
  2799. onSetupPasteable,
  2800. onSetupPasteableColumn,
  2801. onSetupMergeable,
  2802. onSetupUnmergeable,
  2803. resetTargets,
  2804. onSetupTableWithCaption,
  2805. onSetupTableRowHeaders,
  2806. onSetupTableColumnHeaders,
  2807. targets: targets.get
  2808. };
  2809. };
  2810. var global = tinymce.util.Tools.resolve('tinymce.FakeClipboard');
  2811. const tableTypeBase = 'x-tinymce/dom-table-';
  2812. const tableTypeRow = tableTypeBase + 'rows';
  2813. const tableTypeColumn = tableTypeBase + 'columns';
  2814. const getData = type => {
  2815. var _a;
  2816. const items = (_a = global.read()) !== null && _a !== void 0 ? _a : [];
  2817. return findMap(items, item => Optional.from(item.getType(type)));
  2818. };
  2819. const getRows = () => getData(tableTypeRow);
  2820. const getColumns = () => getData(tableTypeColumn);
  2821. const onSetupEditable$1 = editor => api => {
  2822. const nodeChanged = () => {
  2823. api.setEnabled(editor.selection.isEditable());
  2824. };
  2825. editor.on('NodeChange', nodeChanged);
  2826. nodeChanged();
  2827. return () => {
  2828. editor.off('NodeChange', nodeChanged);
  2829. };
  2830. };
  2831. const addButtons = (editor, selectionTargets) => {
  2832. editor.ui.registry.addMenuButton('table', {
  2833. tooltip: 'Table',
  2834. icon: 'table',
  2835. onSetup: onSetupEditable$1(editor),
  2836. fetch: callback => callback('inserttable | cell row column | advtablesort | tableprops deletetable')
  2837. });
  2838. const cmd = command => () => editor.execCommand(command);
  2839. const addButtonIfRegistered = (name, spec) => {
  2840. if (editor.queryCommandSupported(spec.command)) {
  2841. editor.ui.registry.addButton(name, {
  2842. ...spec,
  2843. onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
  2844. });
  2845. }
  2846. };
  2847. const addToggleButtonIfRegistered = (name, spec) => {
  2848. if (editor.queryCommandSupported(spec.command)) {
  2849. editor.ui.registry.addToggleButton(name, {
  2850. ...spec,
  2851. onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
  2852. });
  2853. }
  2854. };
  2855. addButtonIfRegistered('tableprops', {
  2856. tooltip: 'Table properties',
  2857. command: 'mceTableProps',
  2858. icon: 'table',
  2859. onSetup: selectionTargets.onSetupTable
  2860. });
  2861. addButtonIfRegistered('tabledelete', {
  2862. tooltip: 'Delete table',
  2863. command: 'mceTableDelete',
  2864. icon: 'table-delete-table',
  2865. onSetup: selectionTargets.onSetupTable
  2866. });
  2867. addButtonIfRegistered('tablecellprops', {
  2868. tooltip: 'Cell properties',
  2869. command: 'mceTableCellProps',
  2870. icon: 'table-cell-properties',
  2871. onSetup: selectionTargets.onSetupCellOrRow
  2872. });
  2873. addButtonIfRegistered('tablemergecells', {
  2874. tooltip: 'Merge cells',
  2875. command: 'mceTableMergeCells',
  2876. icon: 'table-merge-cells',
  2877. onSetup: selectionTargets.onSetupMergeable
  2878. });
  2879. addButtonIfRegistered('tablesplitcells', {
  2880. tooltip: 'Split cell',
  2881. command: 'mceTableSplitCells',
  2882. icon: 'table-split-cells',
  2883. onSetup: selectionTargets.onSetupUnmergeable
  2884. });
  2885. addButtonIfRegistered('tableinsertrowbefore', {
  2886. tooltip: 'Insert row before',
  2887. command: 'mceTableInsertRowBefore',
  2888. icon: 'table-insert-row-above',
  2889. onSetup: selectionTargets.onSetupCellOrRow
  2890. });
  2891. addButtonIfRegistered('tableinsertrowafter', {
  2892. tooltip: 'Insert row after',
  2893. command: 'mceTableInsertRowAfter',
  2894. icon: 'table-insert-row-after',
  2895. onSetup: selectionTargets.onSetupCellOrRow
  2896. });
  2897. addButtonIfRegistered('tabledeleterow', {
  2898. tooltip: 'Delete row',
  2899. command: 'mceTableDeleteRow',
  2900. icon: 'table-delete-row',
  2901. onSetup: selectionTargets.onSetupCellOrRow
  2902. });
  2903. addButtonIfRegistered('tablerowprops', {
  2904. tooltip: 'Row properties',
  2905. command: 'mceTableRowProps',
  2906. icon: 'table-row-properties',
  2907. onSetup: selectionTargets.onSetupCellOrRow
  2908. });
  2909. addButtonIfRegistered('tableinsertcolbefore', {
  2910. tooltip: 'Insert column before',
  2911. command: 'mceTableInsertColBefore',
  2912. icon: 'table-insert-column-before',
  2913. onSetup: selectionTargets.onSetupColumn('onFirst')
  2914. });
  2915. addButtonIfRegistered('tableinsertcolafter', {
  2916. tooltip: 'Insert column after',
  2917. command: 'mceTableInsertColAfter',
  2918. icon: 'table-insert-column-after',
  2919. onSetup: selectionTargets.onSetupColumn('onLast')
  2920. });
  2921. addButtonIfRegistered('tabledeletecol', {
  2922. tooltip: 'Delete column',
  2923. command: 'mceTableDeleteCol',
  2924. icon: 'table-delete-column',
  2925. onSetup: selectionTargets.onSetupColumn('onAny')
  2926. });
  2927. addButtonIfRegistered('tablecutrow', {
  2928. tooltip: 'Cut row',
  2929. command: 'mceTableCutRow',
  2930. icon: 'cut-row',
  2931. onSetup: selectionTargets.onSetupCellOrRow
  2932. });
  2933. addButtonIfRegistered('tablecopyrow', {
  2934. tooltip: 'Copy row',
  2935. command: 'mceTableCopyRow',
  2936. icon: 'duplicate-row',
  2937. onSetup: selectionTargets.onSetupCellOrRow
  2938. });
  2939. addButtonIfRegistered('tablepasterowbefore', {
  2940. tooltip: 'Paste row before',
  2941. command: 'mceTablePasteRowBefore',
  2942. icon: 'paste-row-before',
  2943. onSetup: selectionTargets.onSetupPasteable(getRows)
  2944. });
  2945. addButtonIfRegistered('tablepasterowafter', {
  2946. tooltip: 'Paste row after',
  2947. command: 'mceTablePasteRowAfter',
  2948. icon: 'paste-row-after',
  2949. onSetup: selectionTargets.onSetupPasteable(getRows)
  2950. });
  2951. addButtonIfRegistered('tablecutcol', {
  2952. tooltip: 'Cut column',
  2953. command: 'mceTableCutCol',
  2954. icon: 'cut-column',
  2955. onSetup: selectionTargets.onSetupColumn('onAny')
  2956. });
  2957. addButtonIfRegistered('tablecopycol', {
  2958. tooltip: 'Copy column',
  2959. command: 'mceTableCopyCol',
  2960. icon: 'duplicate-column',
  2961. onSetup: selectionTargets.onSetupColumn('onAny')
  2962. });
  2963. addButtonIfRegistered('tablepastecolbefore', {
  2964. tooltip: 'Paste column before',
  2965. command: 'mceTablePasteColBefore',
  2966. icon: 'paste-column-before',
  2967. onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')
  2968. });
  2969. addButtonIfRegistered('tablepastecolafter', {
  2970. tooltip: 'Paste column after',
  2971. command: 'mceTablePasteColAfter',
  2972. icon: 'paste-column-after',
  2973. onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')
  2974. });
  2975. addButtonIfRegistered('tableinsertdialog', {
  2976. tooltip: 'Insert table',
  2977. command: 'mceInsertTableDialog',
  2978. icon: 'table',
  2979. onSetup: onSetupEditable$1(editor)
  2980. });
  2981. const tableClassList = filterNoneItem(getTableClassList(editor));
  2982. if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {
  2983. editor.ui.registry.addMenuButton('tableclass', {
  2984. icon: 'table-classes',
  2985. tooltip: 'Table styles',
  2986. fetch: generateMenuItemsCallback(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),
  2987. onSetup: selectionTargets.onSetupTable
  2988. });
  2989. }
  2990. const tableCellClassList = filterNoneItem(getCellClassList(editor));
  2991. if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {
  2992. editor.ui.registry.addMenuButton('tablecellclass', {
  2993. icon: 'table-cell-classes',
  2994. tooltip: 'Cell styles',
  2995. fetch: generateMenuItemsCallback(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),
  2996. onSetup: selectionTargets.onSetupCellOrRow
  2997. });
  2998. }
  2999. if (editor.queryCommandSupported('mceTableApplyCellStyle')) {
  3000. editor.ui.registry.addMenuButton('tablecellvalign', {
  3001. icon: 'vertical-align',
  3002. tooltip: 'Vertical align',
  3003. fetch: generateMenuItemsCallback(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),
  3004. onSetup: selectionTargets.onSetupCellOrRow
  3005. });
  3006. editor.ui.registry.addMenuButton('tablecellborderwidth', {
  3007. icon: 'border-width',
  3008. tooltip: 'Border width',
  3009. fetch: generateMenuItemsCallback(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),
  3010. onSetup: selectionTargets.onSetupCellOrRow
  3011. });
  3012. editor.ui.registry.addMenuButton('tablecellborderstyle', {
  3013. icon: 'border-style',
  3014. tooltip: 'Border style',
  3015. fetch: generateMenuItemsCallback(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),
  3016. onSetup: selectionTargets.onSetupCellOrRow
  3017. });
  3018. editor.ui.registry.addMenuButton('tablecellbackgroundcolor', {
  3019. icon: 'cell-background-color',
  3020. tooltip: 'Background color',
  3021. fetch: callback => callback(buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color')),
  3022. onSetup: selectionTargets.onSetupCellOrRow
  3023. });
  3024. editor.ui.registry.addMenuButton('tablecellbordercolor', {
  3025. icon: 'cell-border-color',
  3026. tooltip: 'Border color',
  3027. fetch: callback => callback(buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color')),
  3028. onSetup: selectionTargets.onSetupCellOrRow
  3029. });
  3030. }
  3031. addToggleButtonIfRegistered('tablecaption', {
  3032. tooltip: 'Table caption',
  3033. icon: 'table-caption',
  3034. command: 'mceTableToggleCaption',
  3035. onSetup: selectionTargets.onSetupTableWithCaption
  3036. });
  3037. addToggleButtonIfRegistered('tablerowheader', {
  3038. tooltip: 'Row header',
  3039. icon: 'table-top-header',
  3040. command: 'mceTableRowType',
  3041. onAction: changeRowHeader(editor),
  3042. onSetup: selectionTargets.onSetupTableRowHeaders
  3043. });
  3044. addToggleButtonIfRegistered('tablecolheader', {
  3045. tooltip: 'Column header',
  3046. icon: 'table-left-header',
  3047. command: 'mceTableColType',
  3048. onAction: changeColumnHeader(editor),
  3049. onSetup: selectionTargets.onSetupTableColumnHeaders
  3050. });
  3051. };
  3052. const addToolbars = editor => {
  3053. const isEditableTable = table => editor.dom.is(table, 'table') && editor.getBody().contains(table) && editor.dom.isEditable(table.parentNode);
  3054. const toolbar = getToolbar(editor);
  3055. if (toolbar.length > 0) {
  3056. editor.ui.registry.addContextToolbar('table', {
  3057. predicate: isEditableTable,
  3058. items: toolbar,
  3059. scope: 'node',
  3060. position: 'node'
  3061. });
  3062. }
  3063. };
  3064. const onSetupEditable = editor => api => {
  3065. const nodeChanged = () => {
  3066. api.setEnabled(editor.selection.isEditable());
  3067. };
  3068. editor.on('NodeChange', nodeChanged);
  3069. nodeChanged();
  3070. return () => {
  3071. editor.off('NodeChange', nodeChanged);
  3072. };
  3073. };
  3074. const addMenuItems = (editor, selectionTargets) => {
  3075. const cmd = command => () => editor.execCommand(command);
  3076. const addMenuIfRegistered = (name, spec) => {
  3077. if (editor.queryCommandSupported(spec.command)) {
  3078. editor.ui.registry.addMenuItem(name, {
  3079. ...spec,
  3080. onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
  3081. });
  3082. return true;
  3083. } else {
  3084. return false;
  3085. }
  3086. };
  3087. const addToggleMenuIfRegistered = (name, spec) => {
  3088. if (editor.queryCommandSupported(spec.command)) {
  3089. editor.ui.registry.addToggleMenuItem(name, {
  3090. ...spec,
  3091. onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)
  3092. });
  3093. }
  3094. };
  3095. const insertTableAction = data => {
  3096. editor.execCommand('mceInsertTable', false, {
  3097. rows: data.numRows,
  3098. columns: data.numColumns
  3099. });
  3100. };
  3101. const hasRowMenuItems = [
  3102. addMenuIfRegistered('tableinsertrowbefore', {
  3103. text: 'Insert row before',
  3104. icon: 'table-insert-row-above',
  3105. command: 'mceTableInsertRowBefore',
  3106. onSetup: selectionTargets.onSetupCellOrRow
  3107. }),
  3108. addMenuIfRegistered('tableinsertrowafter', {
  3109. text: 'Insert row after',
  3110. icon: 'table-insert-row-after',
  3111. command: 'mceTableInsertRowAfter',
  3112. onSetup: selectionTargets.onSetupCellOrRow
  3113. }),
  3114. addMenuIfRegistered('tabledeleterow', {
  3115. text: 'Delete row',
  3116. icon: 'table-delete-row',
  3117. command: 'mceTableDeleteRow',
  3118. onSetup: selectionTargets.onSetupCellOrRow
  3119. }),
  3120. addMenuIfRegistered('tablerowprops', {
  3121. text: 'Row properties',
  3122. icon: 'table-row-properties',
  3123. command: 'mceTableRowProps',
  3124. onSetup: selectionTargets.onSetupCellOrRow
  3125. }),
  3126. addMenuIfRegistered('tablecutrow', {
  3127. text: 'Cut row',
  3128. icon: 'cut-row',
  3129. command: 'mceTableCutRow',
  3130. onSetup: selectionTargets.onSetupCellOrRow
  3131. }),
  3132. addMenuIfRegistered('tablecopyrow', {
  3133. text: 'Copy row',
  3134. icon: 'duplicate-row',
  3135. command: 'mceTableCopyRow',
  3136. onSetup: selectionTargets.onSetupCellOrRow
  3137. }),
  3138. addMenuIfRegistered('tablepasterowbefore', {
  3139. text: 'Paste row before',
  3140. icon: 'paste-row-before',
  3141. command: 'mceTablePasteRowBefore',
  3142. onSetup: selectionTargets.onSetupPasteable(getRows)
  3143. }),
  3144. addMenuIfRegistered('tablepasterowafter', {
  3145. text: 'Paste row after',
  3146. icon: 'paste-row-after',
  3147. command: 'mceTablePasteRowAfter',
  3148. onSetup: selectionTargets.onSetupPasteable(getRows)
  3149. })
  3150. ];
  3151. const hasColumnMenuItems = [
  3152. addMenuIfRegistered('tableinsertcolumnbefore', {
  3153. text: 'Insert column before',
  3154. icon: 'table-insert-column-before',
  3155. command: 'mceTableInsertColBefore',
  3156. onSetup: selectionTargets.onSetupColumn('onFirst')
  3157. }),
  3158. addMenuIfRegistered('tableinsertcolumnafter', {
  3159. text: 'Insert column after',
  3160. icon: 'table-insert-column-after',
  3161. command: 'mceTableInsertColAfter',
  3162. onSetup: selectionTargets.onSetupColumn('onLast')
  3163. }),
  3164. addMenuIfRegistered('tabledeletecolumn', {
  3165. text: 'Delete column',
  3166. icon: 'table-delete-column',
  3167. command: 'mceTableDeleteCol',
  3168. onSetup: selectionTargets.onSetupColumn('onAny')
  3169. }),
  3170. addMenuIfRegistered('tablecutcolumn', {
  3171. text: 'Cut column',
  3172. icon: 'cut-column',
  3173. command: 'mceTableCutCol',
  3174. onSetup: selectionTargets.onSetupColumn('onAny')
  3175. }),
  3176. addMenuIfRegistered('tablecopycolumn', {
  3177. text: 'Copy column',
  3178. icon: 'duplicate-column',
  3179. command: 'mceTableCopyCol',
  3180. onSetup: selectionTargets.onSetupColumn('onAny')
  3181. }),
  3182. addMenuIfRegistered('tablepastecolumnbefore', {
  3183. text: 'Paste column before',
  3184. icon: 'paste-column-before',
  3185. command: 'mceTablePasteColBefore',
  3186. onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')
  3187. }),
  3188. addMenuIfRegistered('tablepastecolumnafter', {
  3189. text: 'Paste column after',
  3190. icon: 'paste-column-after',
  3191. command: 'mceTablePasteColAfter',
  3192. onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')
  3193. })
  3194. ];
  3195. const hasCellMenuItems = [
  3196. addMenuIfRegistered('tablecellprops', {
  3197. text: 'Cell properties',
  3198. icon: 'table-cell-properties',
  3199. command: 'mceTableCellProps',
  3200. onSetup: selectionTargets.onSetupCellOrRow
  3201. }),
  3202. addMenuIfRegistered('tablemergecells', {
  3203. text: 'Merge cells',
  3204. icon: 'table-merge-cells',
  3205. command: 'mceTableMergeCells',
  3206. onSetup: selectionTargets.onSetupMergeable
  3207. }),
  3208. addMenuIfRegistered('tablesplitcells', {
  3209. text: 'Split cell',
  3210. icon: 'table-split-cells',
  3211. command: 'mceTableSplitCells',
  3212. onSetup: selectionTargets.onSetupUnmergeable
  3213. })
  3214. ];
  3215. if (!hasTableGrid(editor)) {
  3216. editor.ui.registry.addMenuItem('inserttable', {
  3217. text: 'Table',
  3218. icon: 'table',
  3219. onAction: cmd('mceInsertTableDialog'),
  3220. onSetup: onSetupEditable(editor)
  3221. });
  3222. } else {
  3223. editor.ui.registry.addNestedMenuItem('inserttable', {
  3224. text: 'Table',
  3225. icon: 'table',
  3226. getSubmenuItems: () => [{
  3227. type: 'fancymenuitem',
  3228. fancytype: 'inserttable',
  3229. onAction: insertTableAction
  3230. }],
  3231. onSetup: onSetupEditable(editor)
  3232. });
  3233. }
  3234. editor.ui.registry.addMenuItem('inserttabledialog', {
  3235. text: 'Insert table',
  3236. icon: 'table',
  3237. onAction: cmd('mceInsertTableDialog'),
  3238. onSetup: onSetupEditable(editor)
  3239. });
  3240. addMenuIfRegistered('tableprops', {
  3241. text: 'Table properties',
  3242. onSetup: selectionTargets.onSetupTable,
  3243. command: 'mceTableProps'
  3244. });
  3245. addMenuIfRegistered('deletetable', {
  3246. text: 'Delete table',
  3247. icon: 'table-delete-table',
  3248. onSetup: selectionTargets.onSetupTable,
  3249. command: 'mceTableDelete'
  3250. });
  3251. if (contains(hasRowMenuItems, true)) {
  3252. editor.ui.registry.addNestedMenuItem('row', {
  3253. type: 'nestedmenuitem',
  3254. text: 'Row',
  3255. getSubmenuItems: constant('tableinsertrowbefore tableinsertrowafter tabledeleterow tablerowprops | tablecutrow tablecopyrow tablepasterowbefore tablepasterowafter')
  3256. });
  3257. }
  3258. if (contains(hasColumnMenuItems, true)) {
  3259. editor.ui.registry.addNestedMenuItem('column', {
  3260. type: 'nestedmenuitem',
  3261. text: 'Column',
  3262. getSubmenuItems: constant('tableinsertcolumnbefore tableinsertcolumnafter tabledeletecolumn | tablecutcolumn tablecopycolumn tablepastecolumnbefore tablepastecolumnafter')
  3263. });
  3264. }
  3265. if (contains(hasCellMenuItems, true)) {
  3266. editor.ui.registry.addNestedMenuItem('cell', {
  3267. type: 'nestedmenuitem',
  3268. text: 'Cell',
  3269. getSubmenuItems: constant('tablecellprops tablemergecells tablesplitcells')
  3270. });
  3271. }
  3272. editor.ui.registry.addContextMenu('table', {
  3273. update: () => {
  3274. selectionTargets.resetTargets();
  3275. return selectionTargets.targets().fold(constant(''), targets => {
  3276. if (name(targets.element) === 'caption') {
  3277. return 'tableprops deletetable';
  3278. } else {
  3279. return 'cell row column | advtablesort | tableprops deletetable';
  3280. }
  3281. });
  3282. }
  3283. });
  3284. const tableClassList = filterNoneItem(getTableClassList(editor));
  3285. if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {
  3286. editor.ui.registry.addNestedMenuItem('tableclass', {
  3287. icon: 'table-classes',
  3288. text: 'Table styles',
  3289. getSubmenuItems: () => buildMenuItems(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),
  3290. onSetup: selectionTargets.onSetupTable
  3291. });
  3292. }
  3293. const tableCellClassList = filterNoneItem(getCellClassList(editor));
  3294. if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {
  3295. editor.ui.registry.addNestedMenuItem('tablecellclass', {
  3296. icon: 'table-cell-classes',
  3297. text: 'Cell styles',
  3298. getSubmenuItems: () => buildMenuItems(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),
  3299. onSetup: selectionTargets.onSetupCellOrRow
  3300. });
  3301. }
  3302. if (editor.queryCommandSupported('mceTableApplyCellStyle')) {
  3303. editor.ui.registry.addNestedMenuItem('tablecellvalign', {
  3304. icon: 'vertical-align',
  3305. text: 'Vertical align',
  3306. getSubmenuItems: () => buildMenuItems(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),
  3307. onSetup: selectionTargets.onSetupCellOrRow
  3308. });
  3309. editor.ui.registry.addNestedMenuItem('tablecellborderwidth', {
  3310. icon: 'border-width',
  3311. text: 'Border width',
  3312. getSubmenuItems: () => buildMenuItems(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),
  3313. onSetup: selectionTargets.onSetupCellOrRow
  3314. });
  3315. editor.ui.registry.addNestedMenuItem('tablecellborderstyle', {
  3316. icon: 'border-style',
  3317. text: 'Border style',
  3318. getSubmenuItems: () => buildMenuItems(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),
  3319. onSetup: selectionTargets.onSetupCellOrRow
  3320. });
  3321. editor.ui.registry.addNestedMenuItem('tablecellbackgroundcolor', {
  3322. icon: 'cell-background-color',
  3323. text: 'Background color',
  3324. getSubmenuItems: () => buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color'),
  3325. onSetup: selectionTargets.onSetupCellOrRow
  3326. });
  3327. editor.ui.registry.addNestedMenuItem('tablecellbordercolor', {
  3328. icon: 'cell-border-color',
  3329. text: 'Border color',
  3330. getSubmenuItems: () => buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color'),
  3331. onSetup: selectionTargets.onSetupCellOrRow
  3332. });
  3333. }
  3334. addToggleMenuIfRegistered('tablecaption', {
  3335. icon: 'table-caption',
  3336. text: 'Table caption',
  3337. command: 'mceTableToggleCaption',
  3338. onSetup: selectionTargets.onSetupTableWithCaption
  3339. });
  3340. addToggleMenuIfRegistered('tablerowheader', {
  3341. text: 'Row header',
  3342. icon: 'table-top-header',
  3343. command: 'mceTableRowType',
  3344. onAction: changeRowHeader(editor),
  3345. onSetup: selectionTargets.onSetupTableRowHeaders
  3346. });
  3347. addToggleMenuIfRegistered('tablecolheader', {
  3348. text: 'Column header',
  3349. icon: 'table-left-header',
  3350. command: 'mceTableColType',
  3351. onAction: changeColumnHeader(editor),
  3352. onSetup: selectionTargets.onSetupTableRowHeaders
  3353. });
  3354. };
  3355. const Plugin = editor => {
  3356. const selectionTargets = getSelectionTargets(editor);
  3357. register(editor);
  3358. registerCommands(editor);
  3359. addMenuItems(editor, selectionTargets);
  3360. addButtons(editor, selectionTargets);
  3361. addToolbars(editor);
  3362. };
  3363. var Plugin$1 = () => {
  3364. global$3.add('table', Plugin);
  3365. };
  3366. Plugin$1();
  3367. })();