plugin.js 76 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172
  1. /**
  2. * TinyMCE version 6.8.6 (TBD)
  3. */
  4. (function () {
  5. 'use strict';
  6. var global$7 = 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 isString = isType$1('string');
  30. const isObject = isType$1('object');
  31. const isArray = isType$1('array');
  32. const isBoolean = isSimpleType('boolean');
  33. const isNullable = a => a === null || a === undefined;
  34. const isNonNullable = a => !isNullable(a);
  35. const isFunction = isSimpleType('function');
  36. const isNumber = isSimpleType('number');
  37. const noop = () => {
  38. };
  39. const compose1 = (fbc, fab) => a => fbc(fab(a));
  40. const constant = value => {
  41. return () => {
  42. return value;
  43. };
  44. };
  45. const tripleEquals = (a, b) => {
  46. return a === b;
  47. };
  48. function curry(fn, ...initialArgs) {
  49. return (...restArgs) => {
  50. const all = initialArgs.concat(restArgs);
  51. return fn.apply(null, all);
  52. };
  53. }
  54. const not = f => t => !f(t);
  55. const never = constant(false);
  56. class Optional {
  57. constructor(tag, value) {
  58. this.tag = tag;
  59. this.value = value;
  60. }
  61. static some(value) {
  62. return new Optional(true, value);
  63. }
  64. static none() {
  65. return Optional.singletonNone;
  66. }
  67. fold(onNone, onSome) {
  68. if (this.tag) {
  69. return onSome(this.value);
  70. } else {
  71. return onNone();
  72. }
  73. }
  74. isSome() {
  75. return this.tag;
  76. }
  77. isNone() {
  78. return !this.tag;
  79. }
  80. map(mapper) {
  81. if (this.tag) {
  82. return Optional.some(mapper(this.value));
  83. } else {
  84. return Optional.none();
  85. }
  86. }
  87. bind(binder) {
  88. if (this.tag) {
  89. return binder(this.value);
  90. } else {
  91. return Optional.none();
  92. }
  93. }
  94. exists(predicate) {
  95. return this.tag && predicate(this.value);
  96. }
  97. forall(predicate) {
  98. return !this.tag || predicate(this.value);
  99. }
  100. filter(predicate) {
  101. if (!this.tag || predicate(this.value)) {
  102. return this;
  103. } else {
  104. return Optional.none();
  105. }
  106. }
  107. getOr(replacement) {
  108. return this.tag ? this.value : replacement;
  109. }
  110. or(replacement) {
  111. return this.tag ? this : replacement;
  112. }
  113. getOrThunk(thunk) {
  114. return this.tag ? this.value : thunk();
  115. }
  116. orThunk(thunk) {
  117. return this.tag ? this : thunk();
  118. }
  119. getOrDie(message) {
  120. if (!this.tag) {
  121. throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');
  122. } else {
  123. return this.value;
  124. }
  125. }
  126. static from(value) {
  127. return isNonNullable(value) ? Optional.some(value) : Optional.none();
  128. }
  129. getOrNull() {
  130. return this.tag ? this.value : null;
  131. }
  132. getOrUndefined() {
  133. return this.value;
  134. }
  135. each(worker) {
  136. if (this.tag) {
  137. worker(this.value);
  138. }
  139. }
  140. toArray() {
  141. return this.tag ? [this.value] : [];
  142. }
  143. toString() {
  144. return this.tag ? `some(${ this.value })` : 'none()';
  145. }
  146. }
  147. Optional.singletonNone = new Optional(false);
  148. const nativeSlice = Array.prototype.slice;
  149. const nativeIndexOf = Array.prototype.indexOf;
  150. const nativePush = Array.prototype.push;
  151. const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);
  152. const contains$1 = (xs, x) => rawIndexOf(xs, x) > -1;
  153. const exists = (xs, pred) => {
  154. for (let i = 0, len = xs.length; i < len; i++) {
  155. const x = xs[i];
  156. if (pred(x, i)) {
  157. return true;
  158. }
  159. }
  160. return false;
  161. };
  162. const map = (xs, f) => {
  163. const len = xs.length;
  164. const r = new Array(len);
  165. for (let i = 0; i < len; i++) {
  166. const x = xs[i];
  167. r[i] = f(x, i);
  168. }
  169. return r;
  170. };
  171. const each$1 = (xs, f) => {
  172. for (let i = 0, len = xs.length; i < len; i++) {
  173. const x = xs[i];
  174. f(x, i);
  175. }
  176. };
  177. const filter$1 = (xs, pred) => {
  178. const r = [];
  179. for (let i = 0, len = xs.length; i < len; i++) {
  180. const x = xs[i];
  181. if (pred(x, i)) {
  182. r.push(x);
  183. }
  184. }
  185. return r;
  186. };
  187. const groupBy = (xs, f) => {
  188. if (xs.length === 0) {
  189. return [];
  190. } else {
  191. let wasType = f(xs[0]);
  192. const r = [];
  193. let group = [];
  194. for (let i = 0, len = xs.length; i < len; i++) {
  195. const x = xs[i];
  196. const type = f(x);
  197. if (type !== wasType) {
  198. r.push(group);
  199. group = [];
  200. }
  201. wasType = type;
  202. group.push(x);
  203. }
  204. if (group.length !== 0) {
  205. r.push(group);
  206. }
  207. return r;
  208. }
  209. };
  210. const foldl = (xs, f, acc) => {
  211. each$1(xs, (x, i) => {
  212. acc = f(acc, x, i);
  213. });
  214. return acc;
  215. };
  216. const findUntil = (xs, pred, until) => {
  217. for (let i = 0, len = xs.length; i < len; i++) {
  218. const x = xs[i];
  219. if (pred(x, i)) {
  220. return Optional.some(x);
  221. } else if (until(x, i)) {
  222. break;
  223. }
  224. }
  225. return Optional.none();
  226. };
  227. const find = (xs, pred) => {
  228. return findUntil(xs, pred, never);
  229. };
  230. const flatten = xs => {
  231. const r = [];
  232. for (let i = 0, len = xs.length; i < len; ++i) {
  233. if (!isArray(xs[i])) {
  234. throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
  235. }
  236. nativePush.apply(r, xs[i]);
  237. }
  238. return r;
  239. };
  240. const bind = (xs, f) => flatten(map(xs, f));
  241. const reverse = xs => {
  242. const r = nativeSlice.call(xs, 0);
  243. r.reverse();
  244. return r;
  245. };
  246. const get$1 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();
  247. const head = xs => get$1(xs, 0);
  248. const last = xs => get$1(xs, xs.length - 1);
  249. const unique = (xs, comparator) => {
  250. const r = [];
  251. const isDuplicated = isFunction(comparator) ? x => exists(r, i => comparator(i, x)) : x => contains$1(r, x);
  252. for (let i = 0, len = xs.length; i < len; i++) {
  253. const x = xs[i];
  254. if (!isDuplicated(x)) {
  255. r.push(x);
  256. }
  257. }
  258. return r;
  259. };
  260. const is$2 = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));
  261. const equals = (lhs, rhs, comparator = tripleEquals) => lift2(lhs, rhs, comparator).getOr(lhs.isNone() && rhs.isNone());
  262. const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();
  263. const COMMENT = 8;
  264. const DOCUMENT = 9;
  265. const DOCUMENT_FRAGMENT = 11;
  266. const ELEMENT = 1;
  267. const TEXT = 3;
  268. const fromHtml = (html, scope) => {
  269. const doc = scope || document;
  270. const div = doc.createElement('div');
  271. div.innerHTML = html;
  272. if (!div.hasChildNodes() || div.childNodes.length > 1) {
  273. const message = 'HTML does not have a single root node';
  274. console.error(message, html);
  275. throw new Error(message);
  276. }
  277. return fromDom$1(div.childNodes[0]);
  278. };
  279. const fromTag = (tag, scope) => {
  280. const doc = scope || document;
  281. const node = doc.createElement(tag);
  282. return fromDom$1(node);
  283. };
  284. const fromText = (text, scope) => {
  285. const doc = scope || document;
  286. const node = doc.createTextNode(text);
  287. return fromDom$1(node);
  288. };
  289. const fromDom$1 = node => {
  290. if (node === null || node === undefined) {
  291. throw new Error('Node cannot be null or undefined');
  292. }
  293. return { dom: node };
  294. };
  295. const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);
  296. const SugarElement = {
  297. fromHtml,
  298. fromTag,
  299. fromText,
  300. fromDom: fromDom$1,
  301. fromPoint
  302. };
  303. const is$1 = (element, selector) => {
  304. const dom = element.dom;
  305. if (dom.nodeType !== ELEMENT) {
  306. return false;
  307. } else {
  308. const elem = dom;
  309. if (elem.matches !== undefined) {
  310. return elem.matches(selector);
  311. } else if (elem.msMatchesSelector !== undefined) {
  312. return elem.msMatchesSelector(selector);
  313. } else if (elem.webkitMatchesSelector !== undefined) {
  314. return elem.webkitMatchesSelector(selector);
  315. } else if (elem.mozMatchesSelector !== undefined) {
  316. return elem.mozMatchesSelector(selector);
  317. } else {
  318. throw new Error('Browser lacks native selectors');
  319. }
  320. }
  321. };
  322. const eq = (e1, e2) => e1.dom === e2.dom;
  323. const contains = (e1, e2) => {
  324. const d1 = e1.dom;
  325. const d2 = e2.dom;
  326. return d1 === d2 ? false : d1.contains(d2);
  327. };
  328. const is = is$1;
  329. const Global = typeof window !== 'undefined' ? window : Function('return this;')();
  330. const path = (parts, scope) => {
  331. let o = scope !== undefined && scope !== null ? scope : Global;
  332. for (let i = 0; i < parts.length && o !== undefined && o !== null; ++i) {
  333. o = o[parts[i]];
  334. }
  335. return o;
  336. };
  337. const resolve = (p, scope) => {
  338. const parts = p.split('.');
  339. return path(parts, scope);
  340. };
  341. const unsafe = (name, scope) => {
  342. return resolve(name, scope);
  343. };
  344. const getOrDie = (name, scope) => {
  345. const actual = unsafe(name, scope);
  346. if (actual === undefined || actual === null) {
  347. throw new Error(name + ' not available on this browser');
  348. }
  349. return actual;
  350. };
  351. const getPrototypeOf = Object.getPrototypeOf;
  352. const sandHTMLElement = scope => {
  353. return getOrDie('HTMLElement', scope);
  354. };
  355. const isPrototypeOf = x => {
  356. const scope = resolve('ownerDocument.defaultView', x);
  357. return isObject(x) && (sandHTMLElement(scope).prototype.isPrototypeOf(x) || /^HTML\w*Element$/.test(getPrototypeOf(x).constructor.name));
  358. };
  359. const name = element => {
  360. const r = element.dom.nodeName;
  361. return r.toLowerCase();
  362. };
  363. const type = element => element.dom.nodeType;
  364. const isType = t => element => type(element) === t;
  365. const isComment = element => type(element) === COMMENT || name(element) === '#comment';
  366. const isHTMLElement = element => isElement$1(element) && isPrototypeOf(element.dom);
  367. const isElement$1 = isType(ELEMENT);
  368. const isText = isType(TEXT);
  369. const isDocument = isType(DOCUMENT);
  370. const isDocumentFragment = isType(DOCUMENT_FRAGMENT);
  371. const isTag = tag => e => isElement$1(e) && name(e) === tag;
  372. const owner = element => SugarElement.fromDom(element.dom.ownerDocument);
  373. const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);
  374. const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);
  375. const parentElement = element => Optional.from(element.dom.parentElement).map(SugarElement.fromDom);
  376. const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);
  377. const children = element => map(element.dom.childNodes, SugarElement.fromDom);
  378. const child = (element, index) => {
  379. const cs = element.dom.childNodes;
  380. return Optional.from(cs[index]).map(SugarElement.fromDom);
  381. };
  382. const firstChild = element => child(element, 0);
  383. const lastChild = element => child(element, element.dom.childNodes.length - 1);
  384. const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);
  385. const supported = isFunction(Element.prototype.attachShadow) && isFunction(Node.prototype.getRootNode);
  386. const getRootNode = supported ? e => SugarElement.fromDom(e.dom.getRootNode()) : documentOrOwner;
  387. const getShadowRoot = e => {
  388. const r = getRootNode(e);
  389. return isShadowRoot(r) ? Optional.some(r) : Optional.none();
  390. };
  391. const getShadowHost = e => SugarElement.fromDom(e.dom.host);
  392. const inBody = element => {
  393. const dom = isText(element) ? element.dom.parentNode : element.dom;
  394. if (dom === undefined || dom === null || dom.ownerDocument === null) {
  395. return false;
  396. }
  397. const doc = dom.ownerDocument;
  398. return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));
  399. };
  400. var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {
  401. if (is(scope, a)) {
  402. return Optional.some(scope);
  403. } else if (isFunction(isRoot) && isRoot(scope)) {
  404. return Optional.none();
  405. } else {
  406. return ancestor(scope, a, isRoot);
  407. }
  408. };
  409. const ancestor$3 = (scope, predicate, isRoot) => {
  410. let element = scope.dom;
  411. const stop = isFunction(isRoot) ? isRoot : never;
  412. while (element.parentNode) {
  413. element = element.parentNode;
  414. const el = SugarElement.fromDom(element);
  415. if (predicate(el)) {
  416. return Optional.some(el);
  417. } else if (stop(el)) {
  418. break;
  419. }
  420. }
  421. return Optional.none();
  422. };
  423. const closest$2 = (scope, predicate, isRoot) => {
  424. const is = (s, test) => test(s);
  425. return ClosestOrAncestor(is, ancestor$3, scope, predicate, isRoot);
  426. };
  427. const ancestor$2 = (scope, selector, isRoot) => ancestor$3(scope, e => is$1(e, selector), isRoot);
  428. const closest$1 = (scope, selector, isRoot) => {
  429. const is = (element, selector) => is$1(element, selector);
  430. return ClosestOrAncestor(is, ancestor$2, scope, selector, isRoot);
  431. };
  432. const closest = target => closest$1(target, '[contenteditable]');
  433. const isEditable = (element, assumeEditable = false) => {
  434. if (inBody(element)) {
  435. return element.dom.isContentEditable;
  436. } else {
  437. return closest(element).fold(constant(assumeEditable), editable => getRaw(editable) === 'true');
  438. }
  439. };
  440. const getRaw = element => element.dom.contentEditable;
  441. const before$1 = (marker, element) => {
  442. const parent$1 = parent(marker);
  443. parent$1.each(v => {
  444. v.dom.insertBefore(element.dom, marker.dom);
  445. });
  446. };
  447. const after = (marker, element) => {
  448. const sibling = nextSibling(marker);
  449. sibling.fold(() => {
  450. const parent$1 = parent(marker);
  451. parent$1.each(v => {
  452. append$1(v, element);
  453. });
  454. }, v => {
  455. before$1(v, element);
  456. });
  457. };
  458. const prepend = (parent, element) => {
  459. const firstChild$1 = firstChild(parent);
  460. firstChild$1.fold(() => {
  461. append$1(parent, element);
  462. }, v => {
  463. parent.dom.insertBefore(element.dom, v.dom);
  464. });
  465. };
  466. const append$1 = (parent, element) => {
  467. parent.dom.appendChild(element.dom);
  468. };
  469. const before = (marker, elements) => {
  470. each$1(elements, x => {
  471. before$1(marker, x);
  472. });
  473. };
  474. const append = (parent, elements) => {
  475. each$1(elements, x => {
  476. append$1(parent, x);
  477. });
  478. };
  479. const empty = element => {
  480. element.dom.textContent = '';
  481. each$1(children(element), rogue => {
  482. remove(rogue);
  483. });
  484. };
  485. const remove = element => {
  486. const dom = element.dom;
  487. if (dom.parentNode !== null) {
  488. dom.parentNode.removeChild(dom);
  489. }
  490. };
  491. var global$6 = tinymce.util.Tools.resolve('tinymce.dom.RangeUtils');
  492. var global$5 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');
  493. var global$4 = tinymce.util.Tools.resolve('tinymce.util.VK');
  494. const fromDom = nodes => map(nodes, SugarElement.fromDom);
  495. const keys = Object.keys;
  496. const each = (obj, f) => {
  497. const props = keys(obj);
  498. for (let k = 0, len = props.length; k < len; k++) {
  499. const i = props[k];
  500. const x = obj[i];
  501. f(x, i);
  502. }
  503. };
  504. const objAcc = r => (x, i) => {
  505. r[i] = x;
  506. };
  507. const internalFilter = (obj, pred, onTrue, onFalse) => {
  508. each(obj, (x, i) => {
  509. (pred(x, i) ? onTrue : onFalse)(x, i);
  510. });
  511. };
  512. const filter = (obj, pred) => {
  513. const t = {};
  514. internalFilter(obj, pred, objAcc(t), noop);
  515. return t;
  516. };
  517. const rawSet = (dom, key, value) => {
  518. if (isString(value) || isBoolean(value) || isNumber(value)) {
  519. dom.setAttribute(key, value + '');
  520. } else {
  521. console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);
  522. throw new Error('Attribute value was not simple');
  523. }
  524. };
  525. const setAll = (element, attrs) => {
  526. const dom = element.dom;
  527. each(attrs, (v, k) => {
  528. rawSet(dom, k, v);
  529. });
  530. };
  531. const clone$1 = element => foldl(element.dom.attributes, (acc, attr) => {
  532. acc[attr.name] = attr.value;
  533. return acc;
  534. }, {});
  535. const clone = (original, isDeep) => SugarElement.fromDom(original.dom.cloneNode(isDeep));
  536. const deep = original => clone(original, true);
  537. const shallowAs = (original, tag) => {
  538. const nu = SugarElement.fromTag(tag);
  539. const attributes = clone$1(original);
  540. setAll(nu, attributes);
  541. return nu;
  542. };
  543. const mutate = (original, tag) => {
  544. const nu = shallowAs(original, tag);
  545. after(original, nu);
  546. const children$1 = children(original);
  547. append(nu, children$1);
  548. remove(original);
  549. return nu;
  550. };
  551. var global$3 = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
  552. var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');
  553. const matchNodeName = name => node => isNonNullable(node) && node.nodeName.toLowerCase() === name;
  554. const matchNodeNames = regex => node => isNonNullable(node) && regex.test(node.nodeName);
  555. const isTextNode$1 = node => isNonNullable(node) && node.nodeType === 3;
  556. const isElement = node => isNonNullable(node) && node.nodeType === 1;
  557. const isListNode = matchNodeNames(/^(OL|UL|DL)$/);
  558. const isOlUlNode = matchNodeNames(/^(OL|UL)$/);
  559. const isOlNode = matchNodeName('ol');
  560. const isListItemNode = matchNodeNames(/^(LI|DT|DD)$/);
  561. const isDlItemNode = matchNodeNames(/^(DT|DD)$/);
  562. const isTableCellNode = matchNodeNames(/^(TH|TD)$/);
  563. const isBr = matchNodeName('br');
  564. const isFirstChild = node => {
  565. var _a;
  566. return ((_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild) === node;
  567. };
  568. const isTextBlock = (editor, node) => isNonNullable(node) && node.nodeName in editor.schema.getTextBlockElements();
  569. const isBlock = (node, blockElements) => isNonNullable(node) && node.nodeName in blockElements;
  570. const isVoid = (editor, node) => isNonNullable(node) && node.nodeName in editor.schema.getVoidElements();
  571. const isBogusBr = (dom, node) => {
  572. if (!isBr(node)) {
  573. return false;
  574. }
  575. return dom.isBlock(node.nextSibling) && !isBr(node.previousSibling);
  576. };
  577. const isEmpty$2 = (dom, elm, keepBookmarks) => {
  578. const empty = dom.isEmpty(elm);
  579. if (keepBookmarks && dom.select('span[data-mce-type=bookmark]', elm).length > 0) {
  580. return false;
  581. }
  582. return empty;
  583. };
  584. const isChildOfBody = (dom, elm) => dom.isChildOf(elm, dom.getRoot());
  585. const option = name => editor => editor.options.get(name);
  586. const register$3 = editor => {
  587. const registerOption = editor.options.register;
  588. registerOption('lists_indent_on_tab', {
  589. processor: 'boolean',
  590. default: true
  591. });
  592. };
  593. const shouldIndentOnTab = option('lists_indent_on_tab');
  594. const getForcedRootBlock = option('forced_root_block');
  595. const getForcedRootBlockAttrs = option('forced_root_block_attrs');
  596. const createTextBlock = (editor, contentNode) => {
  597. const dom = editor.dom;
  598. const blockElements = editor.schema.getBlockElements();
  599. const fragment = dom.createFragment();
  600. const blockName = getForcedRootBlock(editor);
  601. const blockAttrs = getForcedRootBlockAttrs(editor);
  602. let node;
  603. let textBlock;
  604. let hasContentNode = false;
  605. textBlock = dom.create(blockName, blockAttrs);
  606. if (!isBlock(contentNode.firstChild, blockElements)) {
  607. fragment.appendChild(textBlock);
  608. }
  609. while (node = contentNode.firstChild) {
  610. const nodeName = node.nodeName;
  611. if (!hasContentNode && (nodeName !== 'SPAN' || node.getAttribute('data-mce-type') !== 'bookmark')) {
  612. hasContentNode = true;
  613. }
  614. if (isBlock(node, blockElements)) {
  615. fragment.appendChild(node);
  616. textBlock = null;
  617. } else {
  618. if (!textBlock) {
  619. textBlock = dom.create(blockName, blockAttrs);
  620. fragment.appendChild(textBlock);
  621. }
  622. textBlock.appendChild(node);
  623. }
  624. }
  625. if (!hasContentNode && textBlock) {
  626. textBlock.appendChild(dom.create('br', { 'data-mce-bogus': '1' }));
  627. }
  628. return fragment;
  629. };
  630. const DOM$2 = global$3.DOM;
  631. const splitList = (editor, list, li) => {
  632. const removeAndKeepBookmarks = targetNode => {
  633. const parent = targetNode.parentNode;
  634. if (parent) {
  635. global$2.each(bookmarks, node => {
  636. parent.insertBefore(node, li.parentNode);
  637. });
  638. }
  639. DOM$2.remove(targetNode);
  640. };
  641. const bookmarks = DOM$2.select('span[data-mce-type="bookmark"]', list);
  642. const newBlock = createTextBlock(editor, li);
  643. const tmpRng = DOM$2.createRng();
  644. tmpRng.setStartAfter(li);
  645. tmpRng.setEndAfter(list);
  646. const fragment = tmpRng.extractContents();
  647. for (let node = fragment.firstChild; node; node = node.firstChild) {
  648. if (node.nodeName === 'LI' && editor.dom.isEmpty(node)) {
  649. DOM$2.remove(node);
  650. break;
  651. }
  652. }
  653. if (!editor.dom.isEmpty(fragment)) {
  654. DOM$2.insertAfter(fragment, list);
  655. }
  656. DOM$2.insertAfter(newBlock, list);
  657. const parent = li.parentElement;
  658. if (parent && isEmpty$2(editor.dom, parent)) {
  659. removeAndKeepBookmarks(parent);
  660. }
  661. DOM$2.remove(li);
  662. if (isEmpty$2(editor.dom, list)) {
  663. DOM$2.remove(list);
  664. }
  665. };
  666. const isDescriptionDetail = isTag('dd');
  667. const isDescriptionTerm = isTag('dt');
  668. const outdentDlItem = (editor, item) => {
  669. if (isDescriptionDetail(item)) {
  670. mutate(item, 'dt');
  671. } else if (isDescriptionTerm(item)) {
  672. parentElement(item).each(dl => splitList(editor, dl.dom, item.dom));
  673. }
  674. };
  675. const indentDlItem = item => {
  676. if (isDescriptionTerm(item)) {
  677. mutate(item, 'dd');
  678. }
  679. };
  680. const dlIndentation = (editor, indentation, dlItems) => {
  681. if (indentation === 'Indent') {
  682. each$1(dlItems, indentDlItem);
  683. } else {
  684. each$1(dlItems, item => outdentDlItem(editor, item));
  685. }
  686. };
  687. const getNormalizedPoint = (container, offset) => {
  688. if (isTextNode$1(container)) {
  689. return {
  690. container,
  691. offset
  692. };
  693. }
  694. const node = global$6.getNode(container, offset);
  695. if (isTextNode$1(node)) {
  696. return {
  697. container: node,
  698. offset: offset >= container.childNodes.length ? node.data.length : 0
  699. };
  700. } else if (node.previousSibling && isTextNode$1(node.previousSibling)) {
  701. return {
  702. container: node.previousSibling,
  703. offset: node.previousSibling.data.length
  704. };
  705. } else if (node.nextSibling && isTextNode$1(node.nextSibling)) {
  706. return {
  707. container: node.nextSibling,
  708. offset: 0
  709. };
  710. }
  711. return {
  712. container,
  713. offset
  714. };
  715. };
  716. const normalizeRange = rng => {
  717. const outRng = rng.cloneRange();
  718. const rangeStart = getNormalizedPoint(rng.startContainer, rng.startOffset);
  719. outRng.setStart(rangeStart.container, rangeStart.offset);
  720. const rangeEnd = getNormalizedPoint(rng.endContainer, rng.endOffset);
  721. outRng.setEnd(rangeEnd.container, rangeEnd.offset);
  722. return outRng;
  723. };
  724. const listNames = [
  725. 'OL',
  726. 'UL',
  727. 'DL'
  728. ];
  729. const listSelector = listNames.join(',');
  730. const getParentList = (editor, node) => {
  731. const selectionStart = node || editor.selection.getStart(true);
  732. return editor.dom.getParent(selectionStart, listSelector, getClosestListHost(editor, selectionStart));
  733. };
  734. const isParentListSelected = (parentList, selectedBlocks) => isNonNullable(parentList) && selectedBlocks.length === 1 && selectedBlocks[0] === parentList;
  735. const findSubLists = parentList => filter$1(parentList.querySelectorAll(listSelector), isListNode);
  736. const getSelectedSubLists = editor => {
  737. const parentList = getParentList(editor);
  738. const selectedBlocks = editor.selection.getSelectedBlocks();
  739. if (isParentListSelected(parentList, selectedBlocks)) {
  740. return findSubLists(parentList);
  741. } else {
  742. return filter$1(selectedBlocks, elm => {
  743. return isListNode(elm) && parentList !== elm;
  744. });
  745. }
  746. };
  747. const findParentListItemsNodes = (editor, elms) => {
  748. const listItemsElms = global$2.map(elms, elm => {
  749. const parentLi = editor.dom.getParent(elm, 'li,dd,dt', getClosestListHost(editor, elm));
  750. return parentLi ? parentLi : elm;
  751. });
  752. return unique(listItemsElms);
  753. };
  754. const getSelectedListItems = editor => {
  755. const selectedBlocks = editor.selection.getSelectedBlocks();
  756. return filter$1(findParentListItemsNodes(editor, selectedBlocks), isListItemNode);
  757. };
  758. const getSelectedDlItems = editor => filter$1(getSelectedListItems(editor), isDlItemNode);
  759. const getClosestEditingHost = (editor, elm) => {
  760. const parentTableCell = editor.dom.getParents(elm, 'TD,TH');
  761. return parentTableCell.length > 0 ? parentTableCell[0] : editor.getBody();
  762. };
  763. const isListHost = (schema, node) => !isListNode(node) && !isListItemNode(node) && exists(listNames, listName => schema.isValidChild(node.nodeName, listName));
  764. const getClosestListHost = (editor, elm) => {
  765. const parentBlocks = editor.dom.getParents(elm, editor.dom.isBlock);
  766. const parentBlock = find(parentBlocks, elm => isListHost(editor.schema, elm));
  767. return parentBlock.getOr(editor.getBody());
  768. };
  769. const isListInsideAnLiWithFirstAndLastNotListElement = list => parent(list).exists(parent => isListItemNode(parent.dom) && firstChild(parent).exists(firstChild => !isListNode(firstChild.dom)) && lastChild(parent).exists(lastChild => !isListNode(lastChild.dom)));
  770. const findLastParentListNode = (editor, elm) => {
  771. const parentLists = editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
  772. return last(parentLists);
  773. };
  774. const getSelectedLists = editor => {
  775. const firstList = findLastParentListNode(editor, editor.selection.getStart());
  776. const subsequentLists = filter$1(editor.selection.getSelectedBlocks(), isOlUlNode);
  777. return firstList.toArray().concat(subsequentLists);
  778. };
  779. const getParentLists = editor => {
  780. const elm = editor.selection.getStart();
  781. return editor.dom.getParents(elm, 'ol,ul', getClosestListHost(editor, elm));
  782. };
  783. const getSelectedListRoots = editor => {
  784. const selectedLists = getSelectedLists(editor);
  785. const parentLists = getParentLists(editor);
  786. return find(parentLists, p => isListInsideAnLiWithFirstAndLastNotListElement(SugarElement.fromDom(p))).fold(() => getUniqueListRoots(editor, selectedLists), l => [l]);
  787. };
  788. const getUniqueListRoots = (editor, lists) => {
  789. const listRoots = map(lists, list => findLastParentListNode(editor, list).getOr(list));
  790. return unique(listRoots);
  791. };
  792. const isCustomList = list => /\btox\-/.test(list.className);
  793. const inList = (parents, listName) => findUntil(parents, isListNode, isTableCellNode).exists(list => list.nodeName === listName && !isCustomList(list));
  794. const isWithinNonEditable = (editor, element) => element !== null && !editor.dom.isEditable(element);
  795. const selectionIsWithinNonEditableList = editor => {
  796. const parentList = getParentList(editor);
  797. return isWithinNonEditable(editor, parentList);
  798. };
  799. const isWithinNonEditableList = (editor, element) => {
  800. const parentList = editor.dom.getParent(element, 'ol,ul,dl');
  801. return isWithinNonEditable(editor, parentList);
  802. };
  803. const setNodeChangeHandler = (editor, nodeChangeHandler) => {
  804. const initialNode = editor.selection.getNode();
  805. nodeChangeHandler({
  806. parents: editor.dom.getParents(initialNode),
  807. element: initialNode
  808. });
  809. editor.on('NodeChange', nodeChangeHandler);
  810. return () => editor.off('NodeChange', nodeChangeHandler);
  811. };
  812. const fromElements = (elements, scope) => {
  813. const doc = scope || document;
  814. const fragment = doc.createDocumentFragment();
  815. each$1(elements, element => {
  816. fragment.appendChild(element.dom);
  817. });
  818. return SugarElement.fromDom(fragment);
  819. };
  820. const fireListEvent = (editor, action, element) => editor.dispatch('ListMutation', {
  821. action,
  822. element
  823. });
  824. const blank = r => s => s.replace(r, '');
  825. const trim = blank(/^\s+|\s+$/g);
  826. const isNotEmpty = s => s.length > 0;
  827. const isEmpty$1 = s => !isNotEmpty(s);
  828. const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);
  829. const internalSet = (dom, property, value) => {
  830. if (!isString(value)) {
  831. console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);
  832. throw new Error('CSS value must be a string: ' + value);
  833. }
  834. if (isSupported(dom)) {
  835. dom.style.setProperty(property, value);
  836. }
  837. };
  838. const set = (element, property, value) => {
  839. const dom = element.dom;
  840. internalSet(dom, property, value);
  841. };
  842. const isList = el => is(el, 'OL,UL');
  843. const isListItem = el => is(el, 'LI');
  844. const hasFirstChildList = el => firstChild(el).exists(isList);
  845. const hasLastChildList = el => lastChild(el).exists(isList);
  846. const isEntryList = entry => 'listAttributes' in entry;
  847. const isEntryComment = entry => 'isComment' in entry;
  848. const isEntryFragment = entry => 'isFragment' in entry;
  849. const isIndented = entry => entry.depth > 0;
  850. const isSelected = entry => entry.isSelected;
  851. const cloneItemContent = li => {
  852. const children$1 = children(li);
  853. const content = hasLastChildList(li) ? children$1.slice(0, -1) : children$1;
  854. return map(content, deep);
  855. };
  856. const createEntry = (li, depth, isSelected) => parent(li).filter(isElement$1).map(list => ({
  857. depth,
  858. dirty: false,
  859. isSelected,
  860. content: cloneItemContent(li),
  861. itemAttributes: clone$1(li),
  862. listAttributes: clone$1(list),
  863. listType: name(list),
  864. isInPreviousLi: false
  865. }));
  866. const joinSegment = (parent, child) => {
  867. append$1(parent.item, child.list);
  868. };
  869. const joinSegments = segments => {
  870. for (let i = 1; i < segments.length; i++) {
  871. joinSegment(segments[i - 1], segments[i]);
  872. }
  873. };
  874. const appendSegments = (head$1, tail) => {
  875. lift2(last(head$1), head(tail), joinSegment);
  876. };
  877. const createSegment = (scope, listType) => {
  878. const segment = {
  879. list: SugarElement.fromTag(listType, scope),
  880. item: SugarElement.fromTag('li', scope)
  881. };
  882. append$1(segment.list, segment.item);
  883. return segment;
  884. };
  885. const createSegments = (scope, entry, size) => {
  886. const segments = [];
  887. for (let i = 0; i < size; i++) {
  888. segments.push(createSegment(scope, isEntryList(entry) ? entry.listType : entry.parentListType));
  889. }
  890. return segments;
  891. };
  892. const populateSegments = (segments, entry) => {
  893. for (let i = 0; i < segments.length - 1; i++) {
  894. set(segments[i].item, 'list-style-type', 'none');
  895. }
  896. last(segments).each(segment => {
  897. if (isEntryList(entry)) {
  898. setAll(segment.list, entry.listAttributes);
  899. setAll(segment.item, entry.itemAttributes);
  900. }
  901. append(segment.item, entry.content);
  902. });
  903. };
  904. const normalizeSegment = (segment, entry) => {
  905. if (name(segment.list) !== entry.listType) {
  906. segment.list = mutate(segment.list, entry.listType);
  907. }
  908. setAll(segment.list, entry.listAttributes);
  909. };
  910. const createItem = (scope, attr, content) => {
  911. const item = SugarElement.fromTag('li', scope);
  912. setAll(item, attr);
  913. append(item, content);
  914. return item;
  915. };
  916. const appendItem = (segment, item) => {
  917. append$1(segment.list, item);
  918. segment.item = item;
  919. };
  920. const writeShallow = (scope, cast, entry) => {
  921. const newCast = cast.slice(0, entry.depth);
  922. last(newCast).each(segment => {
  923. if (isEntryList(entry)) {
  924. const item = createItem(scope, entry.itemAttributes, entry.content);
  925. appendItem(segment, item);
  926. normalizeSegment(segment, entry);
  927. } else if (isEntryFragment(entry)) {
  928. append(segment.item, entry.content);
  929. } else {
  930. const item = SugarElement.fromHtml(`<!--${ entry.content }-->`);
  931. append$1(segment.list, item);
  932. }
  933. });
  934. return newCast;
  935. };
  936. const writeDeep = (scope, cast, entry) => {
  937. const segments = createSegments(scope, entry, entry.depth - cast.length);
  938. joinSegments(segments);
  939. populateSegments(segments, entry);
  940. appendSegments(cast, segments);
  941. return cast.concat(segments);
  942. };
  943. const composeList = (scope, entries) => {
  944. let firstCommentEntryOpt = Optional.none();
  945. const cast = foldl(entries, (cast, entry, i) => {
  946. if (!isEntryComment(entry)) {
  947. return entry.depth > cast.length ? writeDeep(scope, cast, entry) : writeShallow(scope, cast, entry);
  948. } else {
  949. if (i === 0) {
  950. firstCommentEntryOpt = Optional.some(entry);
  951. return cast;
  952. }
  953. return writeShallow(scope, cast, entry);
  954. }
  955. }, []);
  956. firstCommentEntryOpt.each(firstCommentEntry => {
  957. const item = SugarElement.fromHtml(`<!--${ firstCommentEntry.content }-->`);
  958. head(cast).each(fistCast => {
  959. prepend(fistCast.list, item);
  960. });
  961. });
  962. return head(cast).map(segment => segment.list);
  963. };
  964. const indentEntry = (indentation, entry) => {
  965. switch (indentation) {
  966. case 'Indent':
  967. entry.depth++;
  968. break;
  969. case 'Outdent':
  970. entry.depth--;
  971. break;
  972. case 'Flatten':
  973. entry.depth = 0;
  974. }
  975. entry.dirty = true;
  976. };
  977. const cloneListProperties = (target, source) => {
  978. if (isEntryList(target) && isEntryList(source)) {
  979. target.listType = source.listType;
  980. target.listAttributes = { ...source.listAttributes };
  981. }
  982. };
  983. const cleanListProperties = entry => {
  984. entry.listAttributes = filter(entry.listAttributes, (_value, key) => key !== 'start');
  985. };
  986. const closestSiblingEntry = (entries, start) => {
  987. const depth = entries[start].depth;
  988. const matches = entry => entry.depth === depth && !entry.dirty;
  989. const until = entry => entry.depth < depth;
  990. return findUntil(reverse(entries.slice(0, start)), matches, until).orThunk(() => findUntil(entries.slice(start + 1), matches, until));
  991. };
  992. const normalizeEntries = entries => {
  993. each$1(entries, (entry, i) => {
  994. closestSiblingEntry(entries, i).fold(() => {
  995. if (entry.dirty && isEntryList(entry)) {
  996. cleanListProperties(entry);
  997. }
  998. }, matchingEntry => cloneListProperties(entry, matchingEntry));
  999. });
  1000. return entries;
  1001. };
  1002. const Cell = initial => {
  1003. let value = initial;
  1004. const get = () => {
  1005. return value;
  1006. };
  1007. const set = v => {
  1008. value = v;
  1009. };
  1010. return {
  1011. get,
  1012. set
  1013. };
  1014. };
  1015. const parseSingleItem = (depth, itemSelection, selectionState, item) => {
  1016. var _a;
  1017. if (isComment(item)) {
  1018. return [{
  1019. depth: depth + 1,
  1020. content: (_a = item.dom.nodeValue) !== null && _a !== void 0 ? _a : '',
  1021. dirty: false,
  1022. isSelected: false,
  1023. isComment: true
  1024. }];
  1025. }
  1026. itemSelection.each(selection => {
  1027. if (eq(selection.start, item)) {
  1028. selectionState.set(true);
  1029. }
  1030. });
  1031. const currentItemEntry = createEntry(item, depth, selectionState.get());
  1032. itemSelection.each(selection => {
  1033. if (eq(selection.end, item)) {
  1034. selectionState.set(false);
  1035. }
  1036. });
  1037. const childListEntries = lastChild(item).filter(isList).map(list => parseList(depth, itemSelection, selectionState, list)).getOr([]);
  1038. return currentItemEntry.toArray().concat(childListEntries);
  1039. };
  1040. const parseItem = (depth, itemSelection, selectionState, item) => firstChild(item).filter(isList).fold(() => parseSingleItem(depth, itemSelection, selectionState, item), list => {
  1041. const parsedSiblings = foldl(children(item), (acc, liChild, i) => {
  1042. if (i === 0) {
  1043. return acc;
  1044. } else {
  1045. if (isListItem(liChild)) {
  1046. return acc.concat(parseSingleItem(depth, itemSelection, selectionState, liChild));
  1047. } else {
  1048. const fragment = {
  1049. isFragment: true,
  1050. depth,
  1051. content: [liChild],
  1052. isSelected: false,
  1053. dirty: false,
  1054. parentListType: name(list)
  1055. };
  1056. return acc.concat(fragment);
  1057. }
  1058. }
  1059. }, []);
  1060. return parseList(depth, itemSelection, selectionState, list).concat(parsedSiblings);
  1061. });
  1062. const parseList = (depth, itemSelection, selectionState, list) => bind(children(list), element => {
  1063. const parser = isList(element) ? parseList : parseItem;
  1064. const newDepth = depth + 1;
  1065. return parser(newDepth, itemSelection, selectionState, element);
  1066. });
  1067. const parseLists = (lists, itemSelection) => {
  1068. const selectionState = Cell(false);
  1069. const initialDepth = 0;
  1070. return map(lists, list => ({
  1071. sourceList: list,
  1072. entries: parseList(initialDepth, itemSelection, selectionState, list)
  1073. }));
  1074. };
  1075. const outdentedComposer = (editor, entries) => {
  1076. const normalizedEntries = normalizeEntries(entries);
  1077. return map(normalizedEntries, entry => {
  1078. const content = !isEntryComment(entry) ? fromElements(entry.content) : fromElements([SugarElement.fromHtml(`<!--${ entry.content }-->`)]);
  1079. return SugarElement.fromDom(createTextBlock(editor, content.dom));
  1080. });
  1081. };
  1082. const indentedComposer = (editor, entries) => {
  1083. const normalizedEntries = normalizeEntries(entries);
  1084. return composeList(editor.contentDocument, normalizedEntries).toArray();
  1085. };
  1086. const composeEntries = (editor, entries) => bind(groupBy(entries, isIndented), entries => {
  1087. const groupIsIndented = head(entries).exists(isIndented);
  1088. return groupIsIndented ? indentedComposer(editor, entries) : outdentedComposer(editor, entries);
  1089. });
  1090. const indentSelectedEntries = (entries, indentation) => {
  1091. each$1(filter$1(entries, isSelected), entry => indentEntry(indentation, entry));
  1092. };
  1093. const getItemSelection = editor => {
  1094. const selectedListItems = map(getSelectedListItems(editor), SugarElement.fromDom);
  1095. return lift2(find(selectedListItems, not(hasFirstChildList)), find(reverse(selectedListItems), not(hasFirstChildList)), (start, end) => ({
  1096. start,
  1097. end
  1098. }));
  1099. };
  1100. const listIndentation = (editor, lists, indentation) => {
  1101. const entrySets = parseLists(lists, getItemSelection(editor));
  1102. each$1(entrySets, entrySet => {
  1103. indentSelectedEntries(entrySet.entries, indentation);
  1104. const composedLists = composeEntries(editor, entrySet.entries);
  1105. each$1(composedLists, composedList => {
  1106. fireListEvent(editor, indentation === 'Indent' ? 'IndentList' : 'OutdentList', composedList.dom);
  1107. });
  1108. before(entrySet.sourceList, composedLists);
  1109. remove(entrySet.sourceList);
  1110. });
  1111. };
  1112. const selectionIndentation = (editor, indentation) => {
  1113. const lists = fromDom(getSelectedListRoots(editor));
  1114. const dlItems = fromDom(getSelectedDlItems(editor));
  1115. let isHandled = false;
  1116. if (lists.length || dlItems.length) {
  1117. const bookmark = editor.selection.getBookmark();
  1118. listIndentation(editor, lists, indentation);
  1119. dlIndentation(editor, indentation, dlItems);
  1120. editor.selection.moveToBookmark(bookmark);
  1121. editor.selection.setRng(normalizeRange(editor.selection.getRng()));
  1122. editor.nodeChanged();
  1123. isHandled = true;
  1124. }
  1125. return isHandled;
  1126. };
  1127. const handleIndentation = (editor, indentation) => !selectionIsWithinNonEditableList(editor) && selectionIndentation(editor, indentation);
  1128. const indentListSelection = editor => handleIndentation(editor, 'Indent');
  1129. const outdentListSelection = editor => handleIndentation(editor, 'Outdent');
  1130. const flattenListSelection = editor => handleIndentation(editor, 'Flatten');
  1131. const zeroWidth = '\uFEFF';
  1132. const isZwsp = char => char === zeroWidth;
  1133. const ancestor$1 = (scope, predicate, isRoot) => ancestor$3(scope, predicate, isRoot).isSome();
  1134. const ancestor = (element, target) => ancestor$1(element, curry(eq, target));
  1135. var global$1 = tinymce.util.Tools.resolve('tinymce.dom.BookmarkManager');
  1136. const DOM$1 = global$3.DOM;
  1137. const createBookmark = rng => {
  1138. const bookmark = {};
  1139. const setupEndPoint = start => {
  1140. let container = rng[start ? 'startContainer' : 'endContainer'];
  1141. let offset = rng[start ? 'startOffset' : 'endOffset'];
  1142. if (isElement(container)) {
  1143. const offsetNode = DOM$1.create('span', { 'data-mce-type': 'bookmark' });
  1144. if (container.hasChildNodes()) {
  1145. offset = Math.min(offset, container.childNodes.length - 1);
  1146. if (start) {
  1147. container.insertBefore(offsetNode, container.childNodes[offset]);
  1148. } else {
  1149. DOM$1.insertAfter(offsetNode, container.childNodes[offset]);
  1150. }
  1151. } else {
  1152. container.appendChild(offsetNode);
  1153. }
  1154. container = offsetNode;
  1155. offset = 0;
  1156. }
  1157. bookmark[start ? 'startContainer' : 'endContainer'] = container;
  1158. bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  1159. };
  1160. setupEndPoint(true);
  1161. if (!rng.collapsed) {
  1162. setupEndPoint();
  1163. }
  1164. return bookmark;
  1165. };
  1166. const resolveBookmark = bookmark => {
  1167. const restoreEndPoint = start => {
  1168. const nodeIndex = container => {
  1169. var _a;
  1170. let node = (_a = container.parentNode) === null || _a === void 0 ? void 0 : _a.firstChild;
  1171. let idx = 0;
  1172. while (node) {
  1173. if (node === container) {
  1174. return idx;
  1175. }
  1176. if (!isElement(node) || node.getAttribute('data-mce-type') !== 'bookmark') {
  1177. idx++;
  1178. }
  1179. node = node.nextSibling;
  1180. }
  1181. return -1;
  1182. };
  1183. let container = bookmark[start ? 'startContainer' : 'endContainer'];
  1184. let offset = bookmark[start ? 'startOffset' : 'endOffset'];
  1185. if (!container) {
  1186. return;
  1187. }
  1188. if (isElement(container) && container.parentNode) {
  1189. const node = container;
  1190. offset = nodeIndex(container);
  1191. container = container.parentNode;
  1192. DOM$1.remove(node);
  1193. if (!container.hasChildNodes() && DOM$1.isBlock(container)) {
  1194. container.appendChild(DOM$1.create('br'));
  1195. }
  1196. }
  1197. bookmark[start ? 'startContainer' : 'endContainer'] = container;
  1198. bookmark[start ? 'startOffset' : 'endOffset'] = offset;
  1199. };
  1200. restoreEndPoint(true);
  1201. restoreEndPoint();
  1202. const rng = DOM$1.createRng();
  1203. rng.setStart(bookmark.startContainer, bookmark.startOffset);
  1204. if (bookmark.endContainer) {
  1205. rng.setEnd(bookmark.endContainer, bookmark.endOffset);
  1206. }
  1207. return normalizeRange(rng);
  1208. };
  1209. const listToggleActionFromListName = listName => {
  1210. switch (listName) {
  1211. case 'UL':
  1212. return 'ToggleUlList';
  1213. case 'OL':
  1214. return 'ToggleOlList';
  1215. case 'DL':
  1216. return 'ToggleDLList';
  1217. }
  1218. };
  1219. const updateListStyle = (dom, el, detail) => {
  1220. const type = detail['list-style-type'] ? detail['list-style-type'] : null;
  1221. dom.setStyle(el, 'list-style-type', type);
  1222. };
  1223. const setAttribs = (elm, attrs) => {
  1224. global$2.each(attrs, (value, key) => {
  1225. elm.setAttribute(key, value);
  1226. });
  1227. };
  1228. const updateListAttrs = (dom, el, detail) => {
  1229. setAttribs(el, detail['list-attributes']);
  1230. global$2.each(dom.select('li', el), li => {
  1231. setAttribs(li, detail['list-item-attributes']);
  1232. });
  1233. };
  1234. const updateListWithDetails = (dom, el, detail) => {
  1235. updateListStyle(dom, el, detail);
  1236. updateListAttrs(dom, el, detail);
  1237. };
  1238. const removeStyles = (dom, element, styles) => {
  1239. global$2.each(styles, style => dom.setStyle(element, style, ''));
  1240. };
  1241. const isInline = (editor, node) => isNonNullable(node) && !isBlock(node, editor.schema.getBlockElements());
  1242. const getEndPointNode = (editor, rng, start, root) => {
  1243. let container = rng[start ? 'startContainer' : 'endContainer'];
  1244. const offset = rng[start ? 'startOffset' : 'endOffset'];
  1245. if (isElement(container)) {
  1246. container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
  1247. }
  1248. if (!start && isBr(container.nextSibling)) {
  1249. container = container.nextSibling;
  1250. }
  1251. const findBlockAncestor = node => {
  1252. while (!editor.dom.isBlock(node) && node.parentNode && root !== node) {
  1253. node = node.parentNode;
  1254. }
  1255. return node;
  1256. };
  1257. const findBetterContainer = (container, forward) => {
  1258. var _a;
  1259. const walker = new global$5(container, findBlockAncestor(container));
  1260. const dir = forward ? 'next' : 'prev';
  1261. let node;
  1262. while (node = walker[dir]()) {
  1263. if (!(isVoid(editor, node) || isZwsp(node.textContent) || ((_a = node.textContent) === null || _a === void 0 ? void 0 : _a.length) === 0)) {
  1264. return Optional.some(node);
  1265. }
  1266. }
  1267. return Optional.none();
  1268. };
  1269. if (start && isTextNode$1(container)) {
  1270. if (isZwsp(container.textContent)) {
  1271. container = findBetterContainer(container, false).getOr(container);
  1272. } else {
  1273. if (container.parentNode !== null && isInline(editor, container.parentNode)) {
  1274. container = container.parentNode;
  1275. }
  1276. while (container.previousSibling !== null && (isInline(editor, container.previousSibling) || isTextNode$1(container.previousSibling))) {
  1277. container = container.previousSibling;
  1278. }
  1279. }
  1280. }
  1281. if (!start && isTextNode$1(container)) {
  1282. if (isZwsp(container.textContent)) {
  1283. container = findBetterContainer(container, true).getOr(container);
  1284. } else {
  1285. if (container.parentNode !== null && isInline(editor, container.parentNode)) {
  1286. container = container.parentNode;
  1287. }
  1288. while (container.nextSibling !== null && (isInline(editor, container.nextSibling) || isTextNode$1(container.nextSibling))) {
  1289. container = container.nextSibling;
  1290. }
  1291. }
  1292. }
  1293. while (container.parentNode !== root) {
  1294. const parent = container.parentNode;
  1295. if (isTextBlock(editor, container)) {
  1296. return container;
  1297. }
  1298. if (/^(TD|TH)$/.test(parent.nodeName)) {
  1299. return container;
  1300. }
  1301. container = parent;
  1302. }
  1303. return container;
  1304. };
  1305. const getSelectedTextBlocks = (editor, rng, root) => {
  1306. const textBlocks = [];
  1307. const dom = editor.dom;
  1308. const startNode = getEndPointNode(editor, rng, true, root);
  1309. const endNode = getEndPointNode(editor, rng, false, root);
  1310. let block;
  1311. const siblings = [];
  1312. for (let node = startNode; node; node = node.nextSibling) {
  1313. siblings.push(node);
  1314. if (node === endNode) {
  1315. break;
  1316. }
  1317. }
  1318. global$2.each(siblings, node => {
  1319. var _a;
  1320. if (isTextBlock(editor, node)) {
  1321. textBlocks.push(node);
  1322. block = null;
  1323. return;
  1324. }
  1325. if (dom.isBlock(node) || isBr(node)) {
  1326. if (isBr(node)) {
  1327. dom.remove(node);
  1328. }
  1329. block = null;
  1330. return;
  1331. }
  1332. const nextSibling = node.nextSibling;
  1333. if (global$1.isBookmarkNode(node)) {
  1334. if (isListNode(nextSibling) || isTextBlock(editor, nextSibling) || !nextSibling && node.parentNode === root) {
  1335. block = null;
  1336. return;
  1337. }
  1338. }
  1339. if (!block) {
  1340. block = dom.create('p');
  1341. (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(block, node);
  1342. textBlocks.push(block);
  1343. }
  1344. block.appendChild(node);
  1345. });
  1346. return textBlocks;
  1347. };
  1348. const hasCompatibleStyle = (dom, sib, detail) => {
  1349. const sibStyle = dom.getStyle(sib, 'list-style-type');
  1350. let detailStyle = detail ? detail['list-style-type'] : '';
  1351. detailStyle = detailStyle === null ? '' : detailStyle;
  1352. return sibStyle === detailStyle;
  1353. };
  1354. const getRootSearchStart = (editor, range) => {
  1355. const start = editor.selection.getStart(true);
  1356. const startPoint = getEndPointNode(editor, range, true, editor.getBody());
  1357. if (ancestor(SugarElement.fromDom(startPoint), SugarElement.fromDom(range.commonAncestorContainer))) {
  1358. return range.commonAncestorContainer;
  1359. } else {
  1360. return start;
  1361. }
  1362. };
  1363. const applyList = (editor, listName, detail) => {
  1364. const rng = editor.selection.getRng();
  1365. let listItemName = 'LI';
  1366. const root = getClosestListHost(editor, getRootSearchStart(editor, rng));
  1367. const dom = editor.dom;
  1368. if (dom.getContentEditable(editor.selection.getNode()) === 'false') {
  1369. return;
  1370. }
  1371. listName = listName.toUpperCase();
  1372. if (listName === 'DL') {
  1373. listItemName = 'DT';
  1374. }
  1375. const bookmark = createBookmark(rng);
  1376. const selectedTextBlocks = filter$1(getSelectedTextBlocks(editor, rng, root), editor.dom.isEditable);
  1377. global$2.each(selectedTextBlocks, block => {
  1378. let listBlock;
  1379. const sibling = block.previousSibling;
  1380. const parent = block.parentNode;
  1381. if (!isListItemNode(parent)) {
  1382. if (sibling && isListNode(sibling) && sibling.nodeName === listName && hasCompatibleStyle(dom, sibling, detail)) {
  1383. listBlock = sibling;
  1384. block = dom.rename(block, listItemName);
  1385. sibling.appendChild(block);
  1386. } else {
  1387. listBlock = dom.create(listName);
  1388. parent.insertBefore(listBlock, block);
  1389. listBlock.appendChild(block);
  1390. block = dom.rename(block, listItemName);
  1391. }
  1392. removeStyles(dom, block, [
  1393. 'margin',
  1394. 'margin-right',
  1395. 'margin-bottom',
  1396. 'margin-left',
  1397. 'margin-top',
  1398. 'padding',
  1399. 'padding-right',
  1400. 'padding-bottom',
  1401. 'padding-left',
  1402. 'padding-top'
  1403. ]);
  1404. updateListWithDetails(dom, listBlock, detail);
  1405. mergeWithAdjacentLists(editor.dom, listBlock);
  1406. }
  1407. });
  1408. editor.selection.setRng(resolveBookmark(bookmark));
  1409. };
  1410. const isValidLists = (list1, list2) => {
  1411. return isListNode(list1) && list1.nodeName === (list2 === null || list2 === void 0 ? void 0 : list2.nodeName);
  1412. };
  1413. const hasSameListStyle = (dom, list1, list2) => {
  1414. const targetStyle = dom.getStyle(list1, 'list-style-type', true);
  1415. const style = dom.getStyle(list2, 'list-style-type', true);
  1416. return targetStyle === style;
  1417. };
  1418. const hasSameClasses = (elm1, elm2) => {
  1419. return elm1.className === elm2.className;
  1420. };
  1421. const shouldMerge = (dom, list1, list2) => {
  1422. return isValidLists(list1, list2) && hasSameListStyle(dom, list1, list2) && hasSameClasses(list1, list2);
  1423. };
  1424. const mergeWithAdjacentLists = (dom, listBlock) => {
  1425. let node;
  1426. let sibling = listBlock.nextSibling;
  1427. if (shouldMerge(dom, listBlock, sibling)) {
  1428. const liSibling = sibling;
  1429. while (node = liSibling.firstChild) {
  1430. listBlock.appendChild(node);
  1431. }
  1432. dom.remove(liSibling);
  1433. }
  1434. sibling = listBlock.previousSibling;
  1435. if (shouldMerge(dom, listBlock, sibling)) {
  1436. const liSibling = sibling;
  1437. while (node = liSibling.lastChild) {
  1438. listBlock.insertBefore(node, listBlock.firstChild);
  1439. }
  1440. dom.remove(liSibling);
  1441. }
  1442. };
  1443. const updateList$1 = (editor, list, listName, detail) => {
  1444. if (list.nodeName !== listName) {
  1445. const newList = editor.dom.rename(list, listName);
  1446. updateListWithDetails(editor.dom, newList, detail);
  1447. fireListEvent(editor, listToggleActionFromListName(listName), newList);
  1448. } else {
  1449. updateListWithDetails(editor.dom, list, detail);
  1450. fireListEvent(editor, listToggleActionFromListName(listName), list);
  1451. }
  1452. };
  1453. const updateCustomList = (editor, list, listName, detail) => {
  1454. list.classList.forEach((cls, _, classList) => {
  1455. if (cls.startsWith('tox-')) {
  1456. classList.remove(cls);
  1457. if (classList.length === 0) {
  1458. list.removeAttribute('class');
  1459. }
  1460. }
  1461. });
  1462. if (list.nodeName !== listName) {
  1463. const newList = editor.dom.rename(list, listName);
  1464. updateListWithDetails(editor.dom, newList, detail);
  1465. fireListEvent(editor, listToggleActionFromListName(listName), newList);
  1466. } else {
  1467. updateListWithDetails(editor.dom, list, detail);
  1468. fireListEvent(editor, listToggleActionFromListName(listName), list);
  1469. }
  1470. };
  1471. const toggleMultipleLists = (editor, parentList, lists, listName, detail) => {
  1472. const parentIsList = isListNode(parentList);
  1473. if (parentIsList && parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
  1474. flattenListSelection(editor);
  1475. } else {
  1476. applyList(editor, listName, detail);
  1477. const bookmark = createBookmark(editor.selection.getRng());
  1478. const allLists = parentIsList ? [
  1479. parentList,
  1480. ...lists
  1481. ] : lists;
  1482. const updateFunction = parentIsList && isCustomList(parentList) ? updateCustomList : updateList$1;
  1483. global$2.each(allLists, elm => {
  1484. updateFunction(editor, elm, listName, detail);
  1485. });
  1486. editor.selection.setRng(resolveBookmark(bookmark));
  1487. }
  1488. };
  1489. const hasListStyleDetail = detail => {
  1490. return 'list-style-type' in detail;
  1491. };
  1492. const toggleSingleList = (editor, parentList, listName, detail) => {
  1493. if (parentList === editor.getBody()) {
  1494. return;
  1495. }
  1496. if (parentList) {
  1497. if (parentList.nodeName === listName && !hasListStyleDetail(detail) && !isCustomList(parentList)) {
  1498. flattenListSelection(editor);
  1499. } else {
  1500. const bookmark = createBookmark(editor.selection.getRng());
  1501. if (isCustomList(parentList)) {
  1502. parentList.classList.forEach((cls, _, classList) => {
  1503. if (cls.startsWith('tox-')) {
  1504. classList.remove(cls);
  1505. if (classList.length === 0) {
  1506. parentList.removeAttribute('class');
  1507. }
  1508. }
  1509. });
  1510. }
  1511. updateListWithDetails(editor.dom, parentList, detail);
  1512. const newList = editor.dom.rename(parentList, listName);
  1513. mergeWithAdjacentLists(editor.dom, newList);
  1514. editor.selection.setRng(resolveBookmark(bookmark));
  1515. applyList(editor, listName, detail);
  1516. fireListEvent(editor, listToggleActionFromListName(listName), newList);
  1517. }
  1518. } else {
  1519. applyList(editor, listName, detail);
  1520. fireListEvent(editor, listToggleActionFromListName(listName), parentList);
  1521. }
  1522. };
  1523. const toggleList = (editor, listName, _detail) => {
  1524. const parentList = getParentList(editor);
  1525. if (isWithinNonEditableList(editor, parentList)) {
  1526. return;
  1527. }
  1528. const selectedSubLists = getSelectedSubLists(editor);
  1529. const detail = isObject(_detail) ? _detail : {};
  1530. if (selectedSubLists.length > 0) {
  1531. toggleMultipleLists(editor, parentList, selectedSubLists, listName, detail);
  1532. } else {
  1533. toggleSingleList(editor, parentList, listName, detail);
  1534. }
  1535. };
  1536. const DOM = global$3.DOM;
  1537. const normalizeList = (dom, list) => {
  1538. const parentNode = list.parentElement;
  1539. if (parentNode && parentNode.nodeName === 'LI' && parentNode.firstChild === list) {
  1540. const sibling = parentNode.previousSibling;
  1541. if (sibling && sibling.nodeName === 'LI') {
  1542. sibling.appendChild(list);
  1543. if (isEmpty$2(dom, parentNode)) {
  1544. DOM.remove(parentNode);
  1545. }
  1546. } else {
  1547. DOM.setStyle(parentNode, 'listStyleType', 'none');
  1548. }
  1549. }
  1550. if (isListNode(parentNode)) {
  1551. const sibling = parentNode.previousSibling;
  1552. if (sibling && sibling.nodeName === 'LI') {
  1553. sibling.appendChild(list);
  1554. }
  1555. }
  1556. };
  1557. const normalizeLists = (dom, element) => {
  1558. const lists = global$2.grep(dom.select('ol,ul', element));
  1559. global$2.each(lists, list => {
  1560. normalizeList(dom, list);
  1561. });
  1562. };
  1563. const findNextCaretContainer = (editor, rng, isForward, root) => {
  1564. let node = rng.startContainer;
  1565. const offset = rng.startOffset;
  1566. if (isTextNode$1(node) && (isForward ? offset < node.data.length : offset > 0)) {
  1567. return node;
  1568. }
  1569. const nonEmptyBlocks = editor.schema.getNonEmptyElements();
  1570. if (isElement(node)) {
  1571. node = global$6.getNode(node, offset);
  1572. }
  1573. const walker = new global$5(node, root);
  1574. if (isForward) {
  1575. if (isBogusBr(editor.dom, node)) {
  1576. walker.next();
  1577. }
  1578. }
  1579. const walkFn = isForward ? walker.next.bind(walker) : walker.prev2.bind(walker);
  1580. while (node = walkFn()) {
  1581. if (node.nodeName === 'LI' && !node.hasChildNodes()) {
  1582. return node;
  1583. }
  1584. if (nonEmptyBlocks[node.nodeName]) {
  1585. return node;
  1586. }
  1587. if (isTextNode$1(node) && node.data.length > 0) {
  1588. return node;
  1589. }
  1590. }
  1591. return null;
  1592. };
  1593. const hasOnlyOneBlockChild = (dom, elm) => {
  1594. const childNodes = elm.childNodes;
  1595. return childNodes.length === 1 && !isListNode(childNodes[0]) && dom.isBlock(childNodes[0]);
  1596. };
  1597. const isUnwrappable = node => Optional.from(node).map(SugarElement.fromDom).filter(isHTMLElement).exists(el => isEditable(el) && !contains$1(['details'], name(el)));
  1598. const unwrapSingleBlockChild = (dom, elm) => {
  1599. if (hasOnlyOneBlockChild(dom, elm) && isUnwrappable(elm.firstChild)) {
  1600. dom.remove(elm.firstChild, true);
  1601. }
  1602. };
  1603. const moveChildren = (dom, fromElm, toElm) => {
  1604. let node;
  1605. const targetElm = hasOnlyOneBlockChild(dom, toElm) ? toElm.firstChild : toElm;
  1606. unwrapSingleBlockChild(dom, fromElm);
  1607. if (!isEmpty$2(dom, fromElm, true)) {
  1608. while (node = fromElm.firstChild) {
  1609. targetElm.appendChild(node);
  1610. }
  1611. }
  1612. };
  1613. const mergeLiElements = (dom, fromElm, toElm) => {
  1614. let listNode;
  1615. const ul = fromElm.parentNode;
  1616. if (!isChildOfBody(dom, fromElm) || !isChildOfBody(dom, toElm)) {
  1617. return;
  1618. }
  1619. if (isListNode(toElm.lastChild)) {
  1620. listNode = toElm.lastChild;
  1621. }
  1622. if (ul === toElm.lastChild) {
  1623. if (isBr(ul.previousSibling)) {
  1624. dom.remove(ul.previousSibling);
  1625. }
  1626. }
  1627. const node = toElm.lastChild;
  1628. if (node && isBr(node) && fromElm.hasChildNodes()) {
  1629. dom.remove(node);
  1630. }
  1631. if (isEmpty$2(dom, toElm, true)) {
  1632. empty(SugarElement.fromDom(toElm));
  1633. }
  1634. moveChildren(dom, fromElm, toElm);
  1635. if (listNode) {
  1636. toElm.appendChild(listNode);
  1637. }
  1638. const contains$1 = contains(SugarElement.fromDom(toElm), SugarElement.fromDom(fromElm));
  1639. const nestedLists = contains$1 ? dom.getParents(fromElm, isListNode, toElm) : [];
  1640. dom.remove(fromElm);
  1641. each$1(nestedLists, list => {
  1642. if (isEmpty$2(dom, list) && list !== dom.getRoot()) {
  1643. dom.remove(list);
  1644. }
  1645. });
  1646. };
  1647. const mergeIntoEmptyLi = (editor, fromLi, toLi) => {
  1648. empty(SugarElement.fromDom(toLi));
  1649. mergeLiElements(editor.dom, fromLi, toLi);
  1650. editor.selection.setCursorLocation(toLi, 0);
  1651. };
  1652. const mergeForward = (editor, rng, fromLi, toLi) => {
  1653. const dom = editor.dom;
  1654. if (dom.isEmpty(toLi)) {
  1655. mergeIntoEmptyLi(editor, fromLi, toLi);
  1656. } else {
  1657. const bookmark = createBookmark(rng);
  1658. mergeLiElements(dom, fromLi, toLi);
  1659. editor.selection.setRng(resolveBookmark(bookmark));
  1660. }
  1661. };
  1662. const mergeBackward = (editor, rng, fromLi, toLi) => {
  1663. const bookmark = createBookmark(rng);
  1664. mergeLiElements(editor.dom, fromLi, toLi);
  1665. const resolvedBookmark = resolveBookmark(bookmark);
  1666. editor.selection.setRng(resolvedBookmark);
  1667. };
  1668. const backspaceDeleteFromListToListCaret = (editor, isForward) => {
  1669. const dom = editor.dom, selection = editor.selection;
  1670. const selectionStartElm = selection.getStart();
  1671. const root = getClosestEditingHost(editor, selectionStartElm);
  1672. const li = dom.getParent(selection.getStart(), 'LI', root);
  1673. if (li) {
  1674. const ul = li.parentElement;
  1675. if (ul === editor.getBody() && isEmpty$2(dom, ul)) {
  1676. return true;
  1677. }
  1678. const rng = normalizeRange(selection.getRng());
  1679. const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
  1680. const willMergeParentIntoChild = otherLi && (isForward ? dom.isChildOf(li, otherLi) : dom.isChildOf(otherLi, li));
  1681. if (otherLi && otherLi !== li && !willMergeParentIntoChild) {
  1682. editor.undoManager.transact(() => {
  1683. if (isForward) {
  1684. mergeForward(editor, rng, otherLi, li);
  1685. } else {
  1686. if (isFirstChild(li)) {
  1687. outdentListSelection(editor);
  1688. } else {
  1689. mergeBackward(editor, rng, li, otherLi);
  1690. }
  1691. }
  1692. });
  1693. return true;
  1694. } else if (willMergeParentIntoChild && !isForward && otherLi !== li) {
  1695. editor.undoManager.transact(() => {
  1696. if (rng.commonAncestorContainer.parentElement) {
  1697. const bookmark = createBookmark(rng);
  1698. const oldParentElRef = rng.commonAncestorContainer.parentElement;
  1699. moveChildren(dom, rng.commonAncestorContainer.parentElement, otherLi);
  1700. oldParentElRef.remove();
  1701. const resolvedBookmark = resolveBookmark(bookmark);
  1702. editor.selection.setRng(resolvedBookmark);
  1703. }
  1704. });
  1705. return true;
  1706. } else if (!otherLi) {
  1707. if (!isForward && rng.startOffset === 0 && rng.endOffset === 0) {
  1708. editor.undoManager.transact(() => {
  1709. flattenListSelection(editor);
  1710. });
  1711. return true;
  1712. }
  1713. }
  1714. }
  1715. return false;
  1716. };
  1717. const removeBlock = (dom, block, root) => {
  1718. const parentBlock = dom.getParent(block.parentNode, dom.isBlock, root);
  1719. dom.remove(block);
  1720. if (parentBlock && dom.isEmpty(parentBlock)) {
  1721. dom.remove(parentBlock);
  1722. }
  1723. };
  1724. const backspaceDeleteIntoListCaret = (editor, isForward) => {
  1725. const dom = editor.dom;
  1726. const selectionStartElm = editor.selection.getStart();
  1727. const root = getClosestEditingHost(editor, selectionStartElm);
  1728. const block = dom.getParent(selectionStartElm, dom.isBlock, root);
  1729. if (block && dom.isEmpty(block)) {
  1730. const rng = normalizeRange(editor.selection.getRng());
  1731. const otherLi = dom.getParent(findNextCaretContainer(editor, rng, isForward, root), 'LI', root);
  1732. if (otherLi) {
  1733. const findValidElement = element => contains$1([
  1734. 'td',
  1735. 'th',
  1736. 'caption'
  1737. ], name(element));
  1738. const findRoot = node => node.dom === root;
  1739. const otherLiCell = closest$2(SugarElement.fromDom(otherLi), findValidElement, findRoot);
  1740. const caretCell = closest$2(SugarElement.fromDom(rng.startContainer), findValidElement, findRoot);
  1741. if (!equals(otherLiCell, caretCell, eq)) {
  1742. return false;
  1743. }
  1744. editor.undoManager.transact(() => {
  1745. const parentNode = otherLi.parentNode;
  1746. removeBlock(dom, block, root);
  1747. mergeWithAdjacentLists(dom, parentNode);
  1748. editor.selection.select(otherLi, true);
  1749. editor.selection.collapse(isForward);
  1750. });
  1751. return true;
  1752. }
  1753. }
  1754. return false;
  1755. };
  1756. const backspaceDeleteCaret = (editor, isForward) => {
  1757. return backspaceDeleteFromListToListCaret(editor, isForward) || backspaceDeleteIntoListCaret(editor, isForward);
  1758. };
  1759. const hasListSelection = editor => {
  1760. const selectionStartElm = editor.selection.getStart();
  1761. const root = getClosestEditingHost(editor, selectionStartElm);
  1762. const startListParent = editor.dom.getParent(selectionStartElm, 'LI,DT,DD', root);
  1763. return startListParent || getSelectedListItems(editor).length > 0;
  1764. };
  1765. const backspaceDeleteRange = editor => {
  1766. if (hasListSelection(editor)) {
  1767. editor.undoManager.transact(() => {
  1768. editor.execCommand('Delete');
  1769. normalizeLists(editor.dom, editor.getBody());
  1770. });
  1771. return true;
  1772. }
  1773. return false;
  1774. };
  1775. const backspaceDelete = (editor, isForward) => {
  1776. const selection = editor.selection;
  1777. return !isWithinNonEditableList(editor, selection.getNode()) && (selection.isCollapsed() ? backspaceDeleteCaret(editor, isForward) : backspaceDeleteRange(editor));
  1778. };
  1779. const setup$2 = editor => {
  1780. editor.on('ExecCommand', e => {
  1781. const cmd = e.command.toLowerCase();
  1782. if ((cmd === 'delete' || cmd === 'forwarddelete') && hasListSelection(editor)) {
  1783. normalizeLists(editor.dom, editor.getBody());
  1784. }
  1785. });
  1786. editor.on('keydown', e => {
  1787. if (e.keyCode === global$4.BACKSPACE) {
  1788. if (backspaceDelete(editor, false)) {
  1789. e.preventDefault();
  1790. }
  1791. } else if (e.keyCode === global$4.DELETE) {
  1792. if (backspaceDelete(editor, true)) {
  1793. e.preventDefault();
  1794. }
  1795. }
  1796. });
  1797. };
  1798. const get = editor => ({
  1799. backspaceDelete: isForward => {
  1800. backspaceDelete(editor, isForward);
  1801. }
  1802. });
  1803. const updateList = (editor, update) => {
  1804. const parentList = getParentList(editor);
  1805. if (parentList === null || isWithinNonEditableList(editor, parentList)) {
  1806. return;
  1807. }
  1808. editor.undoManager.transact(() => {
  1809. if (isObject(update.styles)) {
  1810. editor.dom.setStyles(parentList, update.styles);
  1811. }
  1812. if (isObject(update.attrs)) {
  1813. each(update.attrs, (v, k) => editor.dom.setAttrib(parentList, k, v));
  1814. }
  1815. });
  1816. };
  1817. const parseAlphabeticBase26 = str => {
  1818. const chars = reverse(trim(str).split(''));
  1819. const values = map(chars, (char, i) => {
  1820. const charValue = char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0) + 1;
  1821. return Math.pow(26, i) * charValue;
  1822. });
  1823. return foldl(values, (sum, v) => sum + v, 0);
  1824. };
  1825. const composeAlphabeticBase26 = value => {
  1826. value--;
  1827. if (value < 0) {
  1828. return '';
  1829. } else {
  1830. const remainder = value % 26;
  1831. const quotient = Math.floor(value / 26);
  1832. const rest = composeAlphabeticBase26(quotient);
  1833. const char = String.fromCharCode('A'.charCodeAt(0) + remainder);
  1834. return rest + char;
  1835. }
  1836. };
  1837. const isUppercase = str => /^[A-Z]+$/.test(str);
  1838. const isLowercase = str => /^[a-z]+$/.test(str);
  1839. const isNumeric = str => /^[0-9]+$/.test(str);
  1840. const deduceListType = start => {
  1841. if (isNumeric(start)) {
  1842. return 2;
  1843. } else if (isUppercase(start)) {
  1844. return 0;
  1845. } else if (isLowercase(start)) {
  1846. return 1;
  1847. } else if (isEmpty$1(start)) {
  1848. return 3;
  1849. } else {
  1850. return 4;
  1851. }
  1852. };
  1853. const parseStartValue = start => {
  1854. switch (deduceListType(start)) {
  1855. case 2:
  1856. return Optional.some({
  1857. listStyleType: Optional.none(),
  1858. start
  1859. });
  1860. case 0:
  1861. return Optional.some({
  1862. listStyleType: Optional.some('upper-alpha'),
  1863. start: parseAlphabeticBase26(start).toString()
  1864. });
  1865. case 1:
  1866. return Optional.some({
  1867. listStyleType: Optional.some('lower-alpha'),
  1868. start: parseAlphabeticBase26(start).toString()
  1869. });
  1870. case 3:
  1871. return Optional.some({
  1872. listStyleType: Optional.none(),
  1873. start: ''
  1874. });
  1875. case 4:
  1876. return Optional.none();
  1877. }
  1878. };
  1879. const parseDetail = detail => {
  1880. const start = parseInt(detail.start, 10);
  1881. if (is$2(detail.listStyleType, 'upper-alpha')) {
  1882. return composeAlphabeticBase26(start);
  1883. } else if (is$2(detail.listStyleType, 'lower-alpha')) {
  1884. return composeAlphabeticBase26(start).toLowerCase();
  1885. } else {
  1886. return detail.start;
  1887. }
  1888. };
  1889. const open = editor => {
  1890. const currentList = getParentList(editor);
  1891. if (!isOlNode(currentList) || isWithinNonEditableList(editor, currentList)) {
  1892. return;
  1893. }
  1894. editor.windowManager.open({
  1895. title: 'List Properties',
  1896. body: {
  1897. type: 'panel',
  1898. items: [{
  1899. type: 'input',
  1900. name: 'start',
  1901. label: 'Start list at number',
  1902. inputMode: 'numeric'
  1903. }]
  1904. },
  1905. initialData: {
  1906. start: parseDetail({
  1907. start: editor.dom.getAttrib(currentList, 'start', '1'),
  1908. listStyleType: Optional.from(editor.dom.getStyle(currentList, 'list-style-type'))
  1909. })
  1910. },
  1911. buttons: [
  1912. {
  1913. type: 'cancel',
  1914. name: 'cancel',
  1915. text: 'Cancel'
  1916. },
  1917. {
  1918. type: 'submit',
  1919. name: 'save',
  1920. text: 'Save',
  1921. primary: true
  1922. }
  1923. ],
  1924. onSubmit: api => {
  1925. const data = api.getData();
  1926. parseStartValue(data.start).each(detail => {
  1927. editor.execCommand('mceListUpdate', false, {
  1928. attrs: { start: detail.start === '1' ? '' : detail.start },
  1929. styles: { 'list-style-type': detail.listStyleType.getOr('') }
  1930. });
  1931. });
  1932. api.close();
  1933. }
  1934. });
  1935. };
  1936. const queryListCommandState = (editor, listName) => () => {
  1937. const parentList = getParentList(editor);
  1938. return isNonNullable(parentList) && parentList.nodeName === listName;
  1939. };
  1940. const registerDialog = editor => {
  1941. editor.addCommand('mceListProps', () => {
  1942. open(editor);
  1943. });
  1944. };
  1945. const register$2 = editor => {
  1946. editor.on('BeforeExecCommand', e => {
  1947. const cmd = e.command.toLowerCase();
  1948. if (cmd === 'indent') {
  1949. indentListSelection(editor);
  1950. } else if (cmd === 'outdent') {
  1951. outdentListSelection(editor);
  1952. }
  1953. });
  1954. editor.addCommand('InsertUnorderedList', (ui, detail) => {
  1955. toggleList(editor, 'UL', detail);
  1956. });
  1957. editor.addCommand('InsertOrderedList', (ui, detail) => {
  1958. toggleList(editor, 'OL', detail);
  1959. });
  1960. editor.addCommand('InsertDefinitionList', (ui, detail) => {
  1961. toggleList(editor, 'DL', detail);
  1962. });
  1963. editor.addCommand('RemoveList', () => {
  1964. flattenListSelection(editor);
  1965. });
  1966. registerDialog(editor);
  1967. editor.addCommand('mceListUpdate', (ui, detail) => {
  1968. if (isObject(detail)) {
  1969. updateList(editor, detail);
  1970. }
  1971. });
  1972. editor.addQueryStateHandler('InsertUnorderedList', queryListCommandState(editor, 'UL'));
  1973. editor.addQueryStateHandler('InsertOrderedList', queryListCommandState(editor, 'OL'));
  1974. editor.addQueryStateHandler('InsertDefinitionList', queryListCommandState(editor, 'DL'));
  1975. };
  1976. var global = tinymce.util.Tools.resolve('tinymce.html.Node');
  1977. const isTextNode = node => node.type === 3;
  1978. const isEmpty = nodeBuffer => nodeBuffer.length === 0;
  1979. const wrapInvalidChildren = list => {
  1980. const insertListItem = (buffer, refNode) => {
  1981. const li = global.create('li');
  1982. each$1(buffer, node => li.append(node));
  1983. if (refNode) {
  1984. list.insert(li, refNode, true);
  1985. } else {
  1986. list.append(li);
  1987. }
  1988. };
  1989. const reducer = (buffer, node) => {
  1990. if (isTextNode(node)) {
  1991. return [
  1992. ...buffer,
  1993. node
  1994. ];
  1995. } else if (!isEmpty(buffer) && !isTextNode(node)) {
  1996. insertListItem(buffer, node);
  1997. return [];
  1998. } else {
  1999. return buffer;
  2000. }
  2001. };
  2002. const restBuffer = foldl(list.children(), reducer, []);
  2003. if (!isEmpty(restBuffer)) {
  2004. insertListItem(restBuffer);
  2005. }
  2006. };
  2007. const setup$1 = editor => {
  2008. editor.on('PreInit', () => {
  2009. const {parser} = editor;
  2010. parser.addNodeFilter('ul,ol', nodes => each$1(nodes, wrapInvalidChildren));
  2011. });
  2012. };
  2013. const setupTabKey = editor => {
  2014. editor.on('keydown', e => {
  2015. if (e.keyCode !== global$4.TAB || global$4.metaKeyPressed(e)) {
  2016. return;
  2017. }
  2018. editor.undoManager.transact(() => {
  2019. if (e.shiftKey ? outdentListSelection(editor) : indentListSelection(editor)) {
  2020. e.preventDefault();
  2021. }
  2022. });
  2023. });
  2024. };
  2025. const setup = editor => {
  2026. if (shouldIndentOnTab(editor)) {
  2027. setupTabKey(editor);
  2028. }
  2029. setup$2(editor);
  2030. };
  2031. const setupToggleButtonHandler = (editor, listName) => api => {
  2032. const toggleButtonHandler = e => {
  2033. api.setActive(inList(e.parents, listName));
  2034. api.setEnabled(!isWithinNonEditableList(editor, e.element) && editor.selection.isEditable());
  2035. };
  2036. api.setEnabled(editor.selection.isEditable());
  2037. return setNodeChangeHandler(editor, toggleButtonHandler);
  2038. };
  2039. const register$1 = editor => {
  2040. const exec = command => () => editor.execCommand(command);
  2041. if (!editor.hasPlugin('advlist')) {
  2042. editor.ui.registry.addToggleButton('numlist', {
  2043. icon: 'ordered-list',
  2044. active: false,
  2045. tooltip: 'Numbered list',
  2046. onAction: exec('InsertOrderedList'),
  2047. onSetup: setupToggleButtonHandler(editor, 'OL')
  2048. });
  2049. editor.ui.registry.addToggleButton('bullist', {
  2050. icon: 'unordered-list',
  2051. active: false,
  2052. tooltip: 'Bullet list',
  2053. onAction: exec('InsertUnorderedList'),
  2054. onSetup: setupToggleButtonHandler(editor, 'UL')
  2055. });
  2056. }
  2057. };
  2058. const setupMenuButtonHandler = (editor, listName) => api => {
  2059. const menuButtonHandler = e => api.setEnabled(inList(e.parents, listName) && !isWithinNonEditableList(editor, e.element));
  2060. return setNodeChangeHandler(editor, menuButtonHandler);
  2061. };
  2062. const register = editor => {
  2063. const listProperties = {
  2064. text: 'List properties...',
  2065. icon: 'ordered-list',
  2066. onAction: () => editor.execCommand('mceListProps'),
  2067. onSetup: setupMenuButtonHandler(editor, 'OL')
  2068. };
  2069. editor.ui.registry.addMenuItem('listprops', listProperties);
  2070. editor.ui.registry.addContextMenu('lists', {
  2071. update: node => {
  2072. const parentList = getParentList(editor, node);
  2073. return isOlNode(parentList) ? ['listprops'] : [];
  2074. }
  2075. });
  2076. };
  2077. var Plugin = () => {
  2078. global$7.add('lists', editor => {
  2079. register$3(editor);
  2080. setup$1(editor);
  2081. if (!editor.hasPlugin('rtc', true)) {
  2082. setup(editor);
  2083. register$2(editor);
  2084. } else {
  2085. registerDialog(editor);
  2086. }
  2087. register$1(editor);
  2088. register(editor);
  2089. return get(editor);
  2090. });
  2091. };
  2092. Plugin();
  2093. })();