plugin.js 115 KB

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