plugin.js 114 KB

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